package com.authine.cloudpivot.ext.applicationservice.authority;

import com.alibaba.cola.dto.RequestContext;
import com.alibaba.cola.dto.SingleResponse;
import com.alibaba.cola.exception.BizException;
import com.alibaba.cola.exception.Exceptions;
import com.alibaba.fastjson.JSONObject;
import com.authine.cloudpivot.ext.applicationservice.organization.OrganizationApi;
import com.authine.cloudpivot.ext.applicationservice.organization.UserApi;
import com.authine.cloudpivot.ext.constants.AppConst;
import com.authine.cloudpivot.ext.constants.ModelConst;
import com.authine.cloudpivot.ext.constants.PlatformConst;
import com.authine.cloudpivot.ext.dto.ResourceTree;
import com.authine.cloudpivot.ext.dto.RoleQueryDto;
import com.authine.cloudpivot.ext.dto.system.OrganizationDto;
import com.authine.cloudpivot.ext.dto.system.ResourceDto;
import com.authine.cloudpivot.ext.dto.system.RoleDto;
import com.authine.cloudpivot.ext.dto.system.UserDto;
import com.authine.cloudpivot.ext.enums.system.ArchitectureCateEnum;
import com.authine.cloudpivot.ext.enums.system.ResourceTypeEnum;
import com.authine.cloudpivot.ext.enums.system.RowTypeEnum;
import com.authine.cloudpivot.ext.utils.*;
import com.authine.cloudpivot.metadata.design.dto.clientobject.app.AppAllInOne;
import com.authine.cloudpivot.metadata.design.dto.clientobject.domainmodel.schema.BizSchema;
import com.authine.cloudpivot.metadata.design.dto.clientobject.ui.Page;
import com.authine.cloudpivot.metadata.design.dto.clientobject.ui.PageGroup;
import com.authine.common.util.ObjectMapperUtils;
import com.authine.hermes.app.launcher.service.ApplicationService;
import com.authine.hermes.app.operation.admin.dto.clientobject.AppPublishDto;
import com.authine.mvp.app.launcher.common.SchemaHelper;
import com.authine.mvp.app.launcher.domain.SelectorFormat;
import com.authine.mvp.app.launcher.domain.utills.ApplicationContextUtils;
import com.authine.mvp.app.launcher.dto.bo.query.expression.Operator;
import com.authine.mvp.app.launcher.dto.bo.response.BO;
import com.authine.mvp.app.launcher.dto.bo.response.BOList;
import com.authine.mvp.app.launcher.dto.errorcode.ErrorCodeEnum;
import com.authine.mvp.app.launcher.rpc.SaveOrUpdateBO;
import com.authine.mvp.app.permission.dto.clientobject.*;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import javax.ws.rs.POST;
import javax.ws.rs.Path;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static com.authine.hermes.app.launcher.service.ApplicationServiceFoundation.CUSTOM_SERVICE;

/**
 * @ClassName RoleApi
 * @Description: 角色api
 * @Author fj
 * @Date 2021/7/27
 * @Version V1.0
 **/
@Path("RoleApi")
@Slf4j
public class RoleApi extends ApplicationService {
    public static final String SUFFIX_URL = "/app/getMenuTree";
    private final List<String> resourceList = Arrays.asList("hetong.png", "nanyangbaojia.jpg", "nanyangfahuo.jpg", "nanyanghetong.jpg", "pingtai.jpg");
    private static final NamedParameterJdbcTemplate jdbcTemplate = ApplicationContextUtils.getBean(NamedParameterJdbcTemplate.class);

    /**
     * /app/get接口
     * 1.type
     * 0查询UI，模型，流程全部元数据
     * 1 只查询模型
     * 2 只查询流程
     * 3 只查询页面
     * 2.option
     * 0 页面不返回前端页面元数据，模型不返回layout
     * 1 返回所有数据
     */
    public static final String App_GET_PAGE_URL = "/app/get?type=3&option=0";
    public static final String App_GET_DOMAIN_URL = "/app/get?type=1&option=0";
    public static final String PROJECT_CODE = "a71b39d672374ca08cf89847836c0a17";
    private static final String DEFAULT_ID = "2c9ac2dc7cc0c9e7017d09932db6006a";
    private static final String DEFAULT_NAME = "冯杰";
    private static final RestTemplate restTemplate = ApplicationContextUtils.getBean(RestTemplate.class);
    private static final OrganizationApi organizationApi = new OrganizationApi();
    private static final UserApi userApi = new UserApi();

    /**
     * 保存角色信息
     *
     * @param role 角色信息
     * @return 响应结果
     */
    @Path("saveRole")
    @POST
    @Operation(summary = "保存角色信息", tags = CUSTOM_SERVICE)
    public SingleResponse<BO> saveRole(@Parameter RoleDto role) {
        setRoleValue(role);

        if (CollectionUtils.isEmpty(role.getOrganization_id())) {
            boolean pmAdmin = this.existByUserIdAndRoleName(UserDto.builder().id(RequestContext.getCorpLoginId()).roleName(PlatformConst.ROLE_PM_ADMIN).build());
            if (!pmAdmin) {
                throw new BizException("仅平台管理员能创建公共角色");
            }
        }
        checkRoleName(role.getId(), role.getName(), role.getOrganization_name());

        // 添加应用角色组
        List<PermGroupDto> permGroupDtoList = this.addPermGroup(role);

        // 保存角色信息
        Map<String, Object> roleMap = com.authine.cloudpivot.ext.utils.system.BeanUtils.bean2Map(role);
        log.info("------------------------创建系统管理角色参数：{}------------------------", JSONObject.toJSONString(roleMap));
        SingleResponse<BO> createRoleBO = BoServiceUtils.createBo(ModelConst.T_ROLE, Collections.singletonList(roleMap));

        // 根据应用进行分组
        Map<String, List<ResourceDto>> appMapAfterGroupBy = role.getResourceList().stream().collect(Collectors.groupingBy(ResourceDto::getAppCode));
        Set<String> appKeySet = appMapAfterGroupBy.keySet();
        String permGroupId = "";

        // 获取角色名称，判断是供应商还是客户。角色名称规范：ROLE_VENDOR_ADMIN/ROLE_CUSTOMER_ADMIN
        String roleTypeName = role.getName().split("_")[1];

        // 循环遍历每一个应用
        for (String appKey : appKeySet) {
            // 获取应用对应的权限组id
            for (PermGroupDto permGroupDto : permGroupDtoList) {
                if (appKey.equals(permGroupDto.getAppCode())) {
                    permGroupId = permGroupDto.getPermGroupId();
                    break;
                }
            }

            List<ResourceDto> appResourceList = appMapAfterGroupBy.get(appKey);

            updateAppDomain(appKey, permGroupId, createRoleBO.getData().getBizObjectId(), role.getRow_type(), roleTypeName);

            updateAppMenu(appResourceList, permGroupId, createRoleBO.getData().getBizObjectId());

            updateAppPage(appResourceList, permGroupId, createRoleBO.getData().getBizObjectId());
        }

        // 如果没有勾选系统管理，需要在此处自动添加，设置可见范围
        if (!appKeySet.contains(AppConst.SYSTEM_MANAGEMENT)) {
            PermGroupDto first = permGroupDtoList.stream()
                    .filter(permGroupDto -> AppConst.SYSTEM_MANAGEMENT.equals(permGroupDto.getAppCode()))
                    .findFirst()
                    .orElseThrow(() -> new BizException("应用角色组添加失败，请检查数据"));
            updateAppDomain(AppConst.SYSTEM_MANAGEMENT, first.getPermGroupId(), createRoleBO.getData().getBizObjectId(), role.getRow_type(), roleTypeName);
        }

        createRoleResource(createRoleBO.getData().getBizObjectId(), role.getResourceList());

        // 创建组织下的新角色时，需要回写到组织表里
        if (!CollectionUtils.isEmpty(role.getOrganization_id())) {
            // 获取组织信息
            OrganizationDto org = organizationApi.getOrg(OrganizationDto.builder().id(role.getOrganization_id().get(0).getId()).build());
            Map<String, Object> orgMap = Maps.newHashMap();
            orgMap.put("id", role.getOrganization_id().get(0).getId());
            if (StringUtils.isEmpty(org.getRole_names())) {
                orgMap.put("role_names", role.getName());
            } else {
                orgMap.put("role_names", org.getRole_names().concat(",").concat(role.getName()));
            }
            log.info("------------------------修改用户组织：{}------------------------", JSONObject.toJSONString(orgMap));
            BoServiceUtils.updateMainBo(ModelConst.T_ORGANIZATION, orgMap);
        }
        return createRoleBO;
    }

    /**
     * 更新角色信息
     *
     * @param role 角色信息
     * @return 响应结果
     */
    @Path("updateRole")
    @POST
    @Operation(summary = "更新角色信息", tags = CUSTOM_SERVICE)
    public SingleResponse<BO> updateRole(@Parameter RoleDto role) {
        checkRoleName(role.getId(), role.getName(), role.getOrganization_name());

        // 更新应用角色组
        List<PermGroupDto> permGroupDtoList = updatePermGroup(role);

        // 保存角色信息
        Map<String, Object> roleMap = com.authine.cloudpivot.ext.utils.system.BeanUtils.bean2Map(role);
        log.info("------------------------修改系统管理角色参数：{}------------------------", JSONObject.toJSONString(roleMap));
        SingleResponse<BO> updateRoleBO = BoServiceUtils.updateMainBo(ModelConst.T_ROLE, roleMap);
        log.info("------------------------系统管理角色修改成功，修改后角色信息：{}------------------------", JSONObject.toJSONString(updateRoleBO));

        // 通过角色id查询角色权限表
        SingleResponse<BOList> rolePermBOList = BoServiceUtils.findListBySimple(ModelConst.T_ROLE_PERM, "role_id", role.getId());
        log.info("------------------------通过角色id查询角色权限数据列表：{}------------------------", JSONObject.toJSONString(rolePermBOList));

        // 获取需要移除权限的列表(新增时有，修改时没有)
        List<String> removeList = getRemoveList(rolePermBOList, role.getResourceList());
        log.info("------------------------需要移除的权限的应用列表：{}------------------------", JSONObject.toJSONString(removeList));

        if (!CollectionUtils.isEmpty(removeList)) {
            removeList.forEach(appCode -> {
                // 系统管理领域模型权限不删除
                if (!appCode.equals(AppConst.SYSTEM_MANAGEMENT)) {
                    removeAppDomain(appCode, role.getId());
                }
                removeAppMenu(appCode, role.getId());
                removeAppPage(appCode, role.getId());
            });
        }

        // 根据应用进行分组
        Map<String, List<ResourceDto>> appMapAfterGroupBy = role.getResourceList().stream().collect(Collectors.groupingBy(ResourceDto::getAppCode));
        Set<String> appKeySet = appMapAfterGroupBy.keySet();
        String permGroupId = "";

        // 获取角色名称，判断是供应商还是客户。角色名称规范：ROLE_VENDOR_ADMIN/ROLE_CUSTOMER_ADMIN
        String roleTypeName = role.getName().split("_")[1];

        // 循环遍历每一个应用
        for (String appKey : appKeySet) {
            // 获取应用对应的权限组id
            for (PermGroupDto permGroupDto : permGroupDtoList) {
                if (appKey.equals(permGroupDto.getAppCode())) {
                    permGroupId = permGroupDto.getPermGroupId();
                    break;
                }
            }

            updateAppDomain(appKey, permGroupId, updateRoleBO.getData().getBizObjectId(), role.getRow_type(), roleTypeName);

            List<ResourceDto> appResourceList = appMapAfterGroupBy.get(appKey);

            updateAppMenu(appResourceList, permGroupId, updateRoleBO.getData().getBizObjectId());

            // 先移除页面权限，在新增。不然之前的页面权限无法删除
            removeAppPage(appKey, role.getId());

            updateAppPage(appResourceList, permGroupId, updateRoleBO.getData().getBizObjectId());
        }

        // 删除当前角色的角色资源数据
        SingleResponse<BOList> roleResourceBOList = BoServiceUtils.findListBySimple(ModelConst.T_ROLE_RESOURCE, "role_id", role.getId());
        log.info("------------------------通过角色id获取角色资源数据：{}------------------------", JSONObject.toJSONString(roleResourceBOList));
        List<String> bizObjects = roleResourceBOList.getData().getData().stream().map(roleResource -> String.valueOf(roleResource.get("id"))).collect(Collectors.toList());
        BoServiceUtils.batchDeleteBO(ModelConst.T_ROLE_RESOURCE, bizObjects, true);

        // 新增角色资源表数据
        createRoleResource(updateRoleBO.getData().getBizObjectId(), role.getResourceList());
        return updateRoleBO;
    }

    /**
     * 初始化权限资源
     *
     * @return 资源列表
     */
    @Path("initAllResource")
    @POST
    @Operation(summary = "初始化权限资源", tags = CUSTOM_SERVICE)
    public SingleResponse<List<AppPublishDto>> initAllResource() {
        // 获取所有应用列表
        SingleResponse<List<AppPublishDto>> allApp = this.appService.getAllApp(PROJECT_CODE, "");
        log.info("-----------所有应用资源列表：{}---------", allApp);
        int appSort = 1;
        for (AppPublishDto appPublishDto : allApp.getData()) {
            String appCode = appPublishDto.getAppCode();
            if (appCode.equals(AppConst.DEMAND_POOL) || appCode.equals(AppConst.SOURCING_CENTER) || appCode.equals(AppConst.COMMODITYMATERIALS)
                    || appCode.equals(AppConst.ORDER_CENTER) || appCode.equals(AppConst.FINANCIALCENTER) || appCode.equals(AppConst.APPROVAL) || appCode.equals(AppConst.PERSONAL_CENTER)
                    || appCode.equals(AppConst.OPERATION1_CENTER) || appCode.equals(AppConst.GM_MARKET) || appCode.equals(AppConst.SYSTEM_MANAGEMENT)) {
                SingleResponse<?> response = getMenuTree(appCode);

                createResource(response.getData(), appSort++);
            }
        }
        return allApp;
    }

    /**
     * 通过角色id获取角色资源
     *
     * @param role 角色id
     * @return 响应结果
     */
    @Path("getRoleResource")
    @POST
    @Operation(summary = "通过角色id获取角色资源", tags = CUSTOM_SERVICE)
    public List<String> getRoleResource(@Parameter RoleDto role) {
        SingleResponse<BOList> roleResourceBOList = BoServiceUtils.findListBySimple(ModelConst.T_ROLE_RESOURCE, "role_id", role.getId());
        log.info("----------通过角色id获取角色资源列表：{}----------", JSONObject.toJSONString(roleResourceBOList));
        if (roleResourceBOList.getData().getTotal() == 0) {
            return Lists.newArrayList();
        }
        List<String> resourceId = roleResourceBOList.getData().getData().stream()
                .map(roleResource -> String.valueOf(roleResource.get("resource")))
                .distinct()
                .collect(Collectors.toList());
        SingleResponse<BOList> resourceBOList = BoServiceUtils.findListByIn(ModelConst.T_RESOURCE, "id", resourceId);
        log.info("----------通过资源id获取资源列表：{}----------", JSONObject.toJSONString(resourceBOList));
        List<String> checkedKeys = Lists.newArrayList();
        for (Map<String, Object> resourceMap : resourceBOList.getData().getData()) {
            JSONObject keyJSON = new JSONObject();
            keyJSON.put("id", resourceMap.get("id"));
            keyJSON.put("parent_id", resourceMap.get("parent_id"));
            keyJSON.put("name", resourceMap.get("name"));
            keyJSON.put("type", resourceMap.get("type"));
            keyJSON.put("level", ((BigDecimal) resourceMap.get("level")).intValue());
            keyJSON.put("sort", ((BigDecimal) resourceMap.get("sort")).intValue());
            keyJSON.put("appCode", resourceMap.get("appCode"));
            keyJSON.put("permId", resourceMap.get("permId"));
            keyJSON.put("menuCode", resourceMap.get("menuCode"));
            keyJSON.put("groupCode", resourceMap.get("groupCode"));
            keyJSON.put("menuItemCode", resourceMap.get("menuItemCode"));
            keyJSON.put("componentCode", resourceMap.get("componentCode"));
            keyJSON.put("pageCode", resourceMap.get("pageCode"));
            checkedKeys.add(keyJSON.toJSONString());
        }
        return checkedKeys;
    }

    /**
     * 创建资源
     *
     * @param data    资源数据
     * @param appSort 应用排序
     */
    public void createResource(Object data, int appSort) {
        List<Map<String, Object>> appDataList = TypeReferenceUtils.readValueToList(JSONObject.toJSONString(data));
        log.info("----------appDataList：{}----------", JSONObject.toJSONString(appDataList));
        if (CollectionUtils.isEmpty(appDataList)) {
            return;
        }
        Map<String, Object> appDataMap = appDataList.get(0);
        List<Map<String, Object>> resourceDataList = Lists.newArrayList();
        Map<String, Object> appMap = Maps.newHashMap();
        String appId = SchemaHelper.getId();
        appMap.put("id", appId);
        appMap.put("parent_id", null);
        appMap.put("type", ResourceTypeEnum.APP.getCode());
        appMap.put("name", appDataMap.get("appName"));
        appMap.put("level", ResourceTypeEnum.APP.ordinal());
        appMap.put("sort", appSort);
        appMap.put("sortKey", 0);
        appMap.put("appCode", appDataMap.get("appCode"));
        appMap.put("menuCode", null);
        appMap.put("menuItemCode", null);
        appMap.put("groupCode", null);
        appMap.put("componentCode", null);
        appMap.put("pageCode", null);
        appMap.put("leaf", false);
        resourceDataList.add(appMap);
        // 获取菜单项
        if (appDataMap.get("appMenuItems") == null) {
            return;
        }
        List<Map<String, Object>> appMenuItemList = TypeReferenceUtils.readValueToList(JSONObject.toJSONString(appDataMap.get("appMenuItems")));

        appMenuItemList = appMenuItemList.stream()
                // 获取的资源树包含FOLDER和PAGE，只取类型为PAGE的数据
                .filter(appMenuItemMap -> "PAGE".equals(appMenuItemMap.get("menuItemType")) || "URL".equals(appMenuItemMap.get("menuItemType")))
                .collect(Collectors.toList());
        log.info("----------appMenuItemList：{}----------", JSONObject.toJSONString(appMenuItemList));

        for (Map<String, Object> appMenuDataMap : appMenuItemList) {
            Map<String, Object> appMenuMap = Maps.newHashMap();
            String appMenuId = SchemaHelper.getId();
            appMenuMap.put("id", appMenuId);
            appMenuMap.put("parent_id", appId);
            appMenuMap.put("type", ResourceTypeEnum.MENU.getCode());
            appMenuMap.put("name", appMenuDataMap.get("menuItemName"));
            appMenuMap.put("level", ResourceTypeEnum.MENU.ordinal());
            appMenuMap.put("sort", appSort);
            appMenuMap.put("sortKey", appMenuDataMap.get("sortKey"));
            appMenuMap.put("appCode", appDataMap.get("appCode"));
            appMenuMap.put("menuCode", appMenuDataMap.get("menuCode"));
            appMenuMap.put("menuItemCode", appMenuDataMap.get("menuItemCode"));
            appMenuMap.put("leaf", false);
            resourceDataList.add(appMenuMap);
            // 获取标签页
            if (appMenuDataMap.get("TabsPanelContainers") == null) {
                continue;
            }
            List<Map<String, Object>> appTabsPanelList = TypeReferenceUtils.readValueToList(JSONObject.toJSONString(appMenuDataMap.get("TabsPanelContainers")));
            log.info("----------appTabsPanelList：{}----------", JSONObject.toJSONString(appTabsPanelList));
            for (Map<String, Object> appTabsPanelDataMap : appTabsPanelList) {
                Map<String, Object> appTabsPanelMap = Maps.newHashMap();
                String tabsPanelId = SchemaHelper.getId();
                appTabsPanelMap.put("id", tabsPanelId);
                appTabsPanelMap.put("parent_id", appMenuId);
                appTabsPanelMap.put("type", ResourceTypeEnum.TABS.getCode());
                // 获取标签页名称
                Map<String, Object> propsMap = JSONObject.parseObject(JSONObject.toJSONString(appTabsPanelDataMap.get("props")));
                appTabsPanelMap.put("name", propsMap.get("tab"));
                appTabsPanelMap.put("level", ResourceTypeEnum.TABS.ordinal());
                appTabsPanelMap.put("sort", appSort);
                appTabsPanelMap.put("sortKey", 0);
                appTabsPanelMap.put("appCode", appDataMap.get("appCode"));
                appTabsPanelMap.put("componentCode", appTabsPanelDataMap.get("id"));
                appTabsPanelMap.put("groupCode", appMenuDataMap.get("groupCode"));
                appTabsPanelMap.put("pageCode", appMenuDataMap.get("pageCode"));
                appTabsPanelMap.put("leaf", false);
                resourceDataList.add(appTabsPanelMap);
                // 获取菜单项
                if (appTabsPanelDataMap.get("Buttons") == null) {
                    continue;
                }
                List<Map<String, Object>> appButtonList = TypeReferenceUtils.readValueToList(JSONObject.toJSONString(appTabsPanelDataMap.get("Buttons")));
                for (Map<String, Object> appButtonDataMap : appButtonList) {
                    Map<String, Object> appButtonMap = Maps.newHashMap();
                    String buttonId = SchemaHelper.getId();
                    appButtonMap.put("id", buttonId);
                    appButtonMap.put("parent_id", tabsPanelId);
                    appButtonMap.put("type", ResourceTypeEnum.BUTTON.getCode());
                    appButtonMap.put("level", ResourceTypeEnum.BUTTON.ordinal());
                    appButtonMap.put("name", appButtonDataMap.get("name"));
                    appButtonMap.put("sort", appSort);
                    appButtonMap.put("sortKey", 0);
                    appButtonMap.put("appCode", appDataMap.get("appCode"));
                    appButtonMap.put("componentCode", appButtonDataMap.get("id"));
                    appButtonMap.put("groupCode", appMenuDataMap.get("groupCode"));
                    appButtonMap.put("pageCode", appMenuDataMap.get("pageCode"));
                    appButtonMap.put("leaf", true);
                    resourceDataList.add(appButtonMap);
                }
            }
        }
        log.info("------------------------创建应用资源数据，应用名称：{},资源数据：{}------------------------", appDataMap.get("appCode"), JSONObject.toJSONString(resourceDataList));
        BoServiceUtils.createBo(ModelConst.T_RESOURCE, resourceDataList);
    }

    /**
     * 构建资源树
     *
     * @return 资源树
     */
    @Path("buildResourceTree")
    @POST
    @Operation(summary = "构建资源树", tags = CUSTOM_SERVICE)
    public SingleResponse<List<ResourceTree>> buildResourceTree() {
        List<ResourceTree> resourceTreeList = Lists.newArrayList();
        // 获取所有应用资源信息
        String[] columns = new String[]{"enabled", "type"};
        Operator[] operators = new Operator[]{Operator.EQ, Operator.EQ};
        Object[] columnsVal = new Object[]{1, "0"};
        SingleResponse<BOList> appCodeList = BoServiceUtils.findListByComplex(ModelConst.T_RESOURCE, columns, columnsVal, operators);
        if (appCodeList == null || !appCodeList.isSuccess()) {
            throw new BizException("资源数据不存在，请进行应用资源初始化。");
        }
        // 根据应用排序
        appCodeList.getData().getData().sort((o1, o2) -> {
            Integer sort1 = ((BigDecimal) o1.get("sort")).intValue();
            Integer sort2 = ((BigDecimal) o2.get("sort")).intValue();
            return sort1.compareTo(sort2);
        });
        for (Map<String, Object> appMap : appCodeList.getData().getData()) {
            JSONObject keyJSON = new JSONObject();
            keyJSON.put("id", appMap.get("id"));
            keyJSON.put("parent_id", appMap.get("parent_id"));
            keyJSON.put("name", appMap.get("name"));
            keyJSON.put("type", appMap.get("type"));
            keyJSON.put("level", ((BigDecimal) appMap.get("level")).intValue());
            keyJSON.put("sort", ((BigDecimal) appMap.get("sort")).intValue());
            keyJSON.put("appCode", appMap.get("appCode"));
            keyJSON.put("permId", appMap.get("permId"));
            keyJSON.put("menuCode", appMap.get("menuCode"));
            keyJSON.put("groupCode", appMap.get("groupCode"));
            keyJSON.put("menuItemCode", appMap.get("menuItemCode"));
            keyJSON.put("componentCode", appMap.get("componentCode"));
            keyJSON.put("pageCode", appMap.get("pageCode"));
            ResourceTree appResource = ResourceTree.builder()
                    .key(keyJSON.toJSONString())
                    .title(String.valueOf(appMap.get("name")))
                    .build();
            List<ResourceTree> children = getResourceByParentId(String.valueOf(appMap.get("id")));
            appResource.setChildren(children);
            resourceTreeList.add(appResource);
            log.info("------------------------{}应用资源树构建成功，资源树信息：{}------------------------", appMap.get("appCode"), JSONObject.toJSONString(appResource));
        }
        return SingleResponse.of(resourceTreeList);
    }

    /**
     * 新增角色资源关系
     *
     * @param roleDto 角色信息
     * @return 响应结果
     */
    @Path("addRoleResource")
    @POST
    @Operation(summary = "新增角色资源关系", tags = CUSTOM_SERVICE)
    public SingleResponse<BO> addRoleResource(@Parameter RoleDto roleDto) {
        Assert.notNull(roleDto.getId(), "角色id不能为空");
        Assert.notNull(roleDto.getResourceId(), "资源id不能为空");

        // 通过角色id查询角色信息
        SingleResponse<BO> roleBO = BoServiceUtils.loadBo(roleDto.getId(), ModelConst.T_ROLE);
        log.info("------------------------通过角色id查询角色信息：{}------------------------", JSONObject.toJSONString(roleBO));
        if (!roleBO.isSuccess()) {
            Exceptions.throwBizException(ErrorCodeEnum.BO_GET_ERROR);
        }
        RoleDto role = ObjectMapperUtils.fromJSON(ObjectMapperUtils.toJSONString(roleBO.getData().getData()), RoleDto.class);

        // 通过资源id查询资源信息
        SingleResponse<BO> resourceBO = BoServiceUtils.loadBo(roleDto.getResourceId(), ModelConst.T_RESOURCE);
        log.info("------------------------通过资源id查询资源信息：{}------------------------", JSONObject.toJSONString(resourceBO));
        ResourceDto resource = ObjectMapperUtils.fromJSON(ObjectMapperUtils.toJSONString(resourceBO.getData().getData()), ResourceDto.class);

        // 通过角色id查询角色资源表数据
        SingleResponse<BOList> roleResourceBOList = BoServiceUtils.findListBySimple(ModelConst.T_ROLE_RESOURCE, "role_id", role.getId());
        log.info("------------------------通过角色id查询角色资源数据列表：{}------------------------", JSONObject.toJSONString(roleResourceBOList));

        // 获取角色关联的资源id
        List<ResourceDto> resourceList;
        List<String> resourceIdList = roleResourceBOList.getData().getData().stream().map(map -> String.valueOf(map.get("resource"))).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(resourceIdList)) {
            // 通过资源id获取资源列表
            SingleResponse<BOList> resourceBOList = BoServiceUtils.findListByIn(ModelConst.T_RESOURCE, "id", resourceIdList);
            log.info("------------------------通过资源id列表查询资源列表数据：{}------------------------", JSONObject.toJSONString(roleResourceBOList));
            resourceList = ObjectMapperUtils.readValue(ObjectMapperUtils.toJSONString(resourceBOList.getData().getData()), ResourceDto.class);
        } else {
            resourceList = Lists.newArrayList();
        }

        // 新增资源
        resourceList.add(resource);
        role.setResourceList(resourceList);

        // 更新应用角色组
        List<PermGroupDto> permGroupDtoList = updatePermGroup(role);

        // 根据应用进行分组
        Map<String, List<ResourceDto>> appMapAfterGroupBy = role.getResourceList().stream().collect(Collectors.groupingBy(ResourceDto::getAppCode));
        Set<String> appKeySet = appMapAfterGroupBy.keySet();
        String permGroupId = "";

        // 循环遍历每一个应用
        for (String appKey : appKeySet) {
            // 获取应用对应的权限组id
            for (PermGroupDto permGroupDto : permGroupDtoList) {
                if (appKey.equals(permGroupDto.getAppCode())) {
                    permGroupId = permGroupDto.getPermGroupId();
                    break;
                }
            }
            List<ResourceDto> appResourceList = appMapAfterGroupBy.get(appKey);

            updateAppMenu(appResourceList, permGroupId, role.getId());

            updateAppPage(appResourceList, permGroupId, role.getId());
        }

        createRoleResource(role.getId(), Collections.singletonList(resource));
        return roleBO;
    }

    /**
     * 解除角色资源关系
     *
     * @param roleDto 角色信息
     * @return 响应结果
     */
    @Path("removeRoleResource")
    @POST
    @Operation(summary = "解除角色资源关系", tags = CUSTOM_SERVICE)
    public SingleResponse<BO> removeRoleResource(@Parameter RoleDto roleDto) {
        Assert.notNull(roleDto.getId(), "角色id不能为空");
        Assert.notNull(roleDto.getResourceId(), "资源id不能为空");

        // 通过角色id查询角色信息
        SingleResponse<BO> roleBO = BoServiceUtils.loadBo(roleDto.getId(), ModelConst.T_ROLE);
        log.info("------------------------通过角色id查询角色信息：{}------------------------", JSONObject.toJSONString(roleBO));
        if (!roleBO.isSuccess()) {
            Exceptions.throwBizException(ErrorCodeEnum.BO_GET_ERROR);
        }
        RoleDto role = ObjectMapperUtils.fromJSON(ObjectMapperUtils.toJSONString(roleBO.getData().getData()), RoleDto.class);

        // 通过资源id查询资源信息
        SingleResponse<BO> resourceBO = BoServiceUtils.loadBo(roleDto.getResourceId(), ModelConst.T_RESOURCE);
        log.info("------------------------通过资源id查询资源信息：{}------------------------", JSONObject.toJSONString(resourceBO));
        ResourceDto resource = ObjectMapperUtils.fromJSON(ObjectMapperUtils.toJSONString(resourceBO.getData().getData()), ResourceDto.class);

        // 通过角色id查询角色资源表数据
        SingleResponse<BOList> roleResourceBOList = BoServiceUtils.findListBySimple(ModelConst.T_ROLE_RESOURCE, "role_id", role.getId());
        log.info("------------------------通过角色id查询角色资源数据列表：{}------------------------", JSONObject.toJSONString(roleResourceBOList));

        // 获取角色关联的资源id
        List<String> resourceIdList = roleResourceBOList.getData().getData().stream().map(map -> String.valueOf(map.get("resource"))).collect(Collectors.toList());

        // 通过资源id获取资源列表
        SingleResponse<BOList> resourceBOList = BoServiceUtils.findListByIn(ModelConst.T_RESOURCE, "id", resourceIdList);
        log.info("------------------------通过资源id列表查询资源列表数据：{}------------------------", JSONObject.toJSONString(roleResourceBOList));

        // 新增资源
        List<ResourceDto> resourceList = ObjectMapperUtils.readValue(ObjectMapperUtils.toJSONString(resourceBOList.getData().getData()), ResourceDto.class);
        resourceList.remove(resource);
        role.setResourceList(resourceList);

        // 获取角色权限组id
        String[] columnNames = new String[]{"role_id", "app_code"};
        Operator[] operators = new Operator[]{Operator.EQ, Operator.EQ};
        Object[] columnValues = new Object[]{role.getId(), resource.getAppCode()};
        SingleResponse<BOList> rolePermBOList = BoServiceUtils.findListByComplex(ModelConst.T_ROLE_PERM, columnNames, columnValues, operators);
        log.info("------------------------通过角色id和应用编码查询角色权限数据：{}------------------------", JSONObject.toJSONString(rolePermBOList));
        String permGroupId = String.valueOf(rolePermBOList.getData().getData().get(0).get("group_id"));

        // 获取资源类型为菜单的数据
        List<ResourceDto> menuResourceList = resourceList.stream().filter(resourceDto -> ResourceTypeEnum.MENU.getCode().equals(resourceDto.getType())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(menuResourceList)) {
            removeAppMenu(resource.getAppCode(), roleDto.getId());
        } else {
            updateAppMenu(resourceList, permGroupId, role.getId());
        }

        // 获取资源类型为菜单的数据
        List<ResourceDto> pageResourceList = resourceList.stream().filter(resourceDto -> ResourceTypeEnum.TABS.getCode().equals(resourceDto.getType())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(pageResourceList)) {
            removeAppPage(resource.getAppCode(), roleDto.getId());
        } else {
            updateAppPage(resourceList, permGroupId, role.getId());
        }

        // 应用下没有资源，删除角色组领域模型权限
        if (CollectionUtils.isEmpty(resourceList)) {
            removeAppDomain(resource.getAppCode(), roleDto.getId());
        }

        // 删除角色资源表数据
        columnNames = new String[]{"role_id", "resource"};
        operators = new Operator[]{Operator.EQ, Operator.EQ};
        columnValues = new Object[]{role.getId(), resource.getId()};
        SingleResponse<BOList> roleResourceBOListByRoleIdAndResourceId = BoServiceUtils.findListByComplex(ModelConst.T_ROLE_RESOURCE, columnNames, columnValues, operators);
        String bizObjectId = String.valueOf(roleResourceBOListByRoleIdAndResourceId.getData().getData().get(0).get("id"));
        BoServiceUtils.deleteBo(ModelConst.T_ROLE_RESOURCE, bizObjectId, true);
        return roleBO;
    }

    /**
     * 根据组织id和角色名称获取角色列表
     *
     * @param role 角色信息
     * @return 角色列表
     */
    @Path("getRolesByOrgIdAndNames")
    @POST
    @Operation(summary = "根据组织id和角色名称获取角色列表", tags = CUSTOM_SERVICE)
    public List<RoleDto> getRolesByOrgIdAndNames(@Parameter RoleDto role) {
        String[] columns = new String[]{"name", "organization_id"};
        Operator[] operators = new Operator[]{Operator.IN, Operator.EQ};
        Object[] columnsVal = new Object[]{role.getNames(), role.getOrganization_id().get(0).getId()};
        SingleResponse<BOList> roleBOList = BoServiceUtils.findListByComplex(ModelConst.T_ROLE, columns, columnsVal, operators);
        if (!roleBOList.isSuccess()) {
            Exceptions.throwBizException(ErrorCodeEnum.BO_LIST_ERROR);
        }
        log.info("------------------------根据组织id和角色名称获取角色列表返回结果：{}------------------------", JSONObject.toJSONString(roleBOList));
        if (roleBOList.getData().getTotal() == 0) {
            return Lists.newArrayList();
        }
        return ObjectMapperUtils.readValue(JSONObject.toJSONString(roleBOList.getData().getData()), RoleDto.class);
    }

    /**
     * 根据组织id和角色名称判断角色是否存在
     *
     * @param role 角色信息
     * @return true：存在  false：不存在
     */
    @Path("existByOrgIdAndRoleName")
    @POST
    @Operation(summary = "根据组织id和角色名称判断角色是否存在", tags = CUSTOM_SERVICE)
    public boolean existByOrgIdAndRoleName(@Parameter RoleDto role) {
        Assert.notNull(role.getName(), "角色名称不能为空");

        String[] columns = new String[]{"name", "organization_id"};
        Operator[] operators = new Operator[]{Operator.EQ, Operator.LIKE};
        Object[] columnsVal = new Object[2];
        columnsVal[0] = role.getName();
        if (CollectionUtils.isEmpty(role.getOrganization_id())) {
            operators[1] = Operator.IS_NULL;
            columnsVal[1] = null;
        } else {
            columnsVal[1] = role.getOrganization_id().get(0);
        }
        SingleResponse<BOList> roleBOList = BoServiceUtils.findListByComplex(ModelConst.T_ROLE, columns, columnsVal, operators);
        if (!roleBOList.isSuccess()) {
            Exceptions.throwBizException(ErrorCodeEnum.BO_LIST_ERROR);
        }
        log.info("------------------------根据组织id和角色名称获取角色列表返回结果：{}------------------------", JSONObject.toJSONString(roleBOList));
        return roleBOList.getData().getTotal() > 0;
    }

    /**
     * 根据用户id和角色名称判断角色是否存在
     *
     * @param userDto 用户信息
     * @return true：存在  false：不存在
     */
    @Path("existByUserIdAndRoleName")
    @POST
    @Operation(summary = "根据用户id和角色名称判断角色是否存在", tags = CUSTOM_SERVICE)
    public boolean existByUserIdAndRoleName(@Parameter UserDto userDto) {
        Assert.notNull(userDto.getId(), "用户id不能为空");

        UserDto user = userApi.getUser(UserDto.builder().id(userDto.getId()).build());
        List<String> roleIds = Arrays.asList(user.getRole_ids().split(","));
        SingleResponse<BOList> roleBOList = BoServiceUtils.findListByIn(ModelConst.T_ROLE, "id", roleIds);
        if (!roleBOList.isSuccess()) {
            Exceptions.throwBizException(ErrorCodeEnum.BO_LIST_ERROR);
        }
        log.info("------------------------根据用户id和角色名称获取角色列表返回结果：{}------------------------", JSONObject.toJSONString(roleBOList));
        boolean result = false;
        // 判断是否包含该角色名称
        if (roleBOList.getData().getTotal() > 0) {
            result = roleBOList.getData().getData().stream().map(roleMap -> String.valueOf(roleMap.get("name"))).collect(Collectors.toList())
                    .contains(userDto.getRoleName());
        }
        return result;
    }

    /**
     * 根据组织id获取所有管理员角色架构
     * ArchitectureCateEnum 是临时的 以后可能改成：Architecture
     * 架构类型 也是一种角色 一个组织 可以拥有多个架构类型
     *
     * @param roleDto 角色信息
     * @return 管理员角色集合
     */
    @Path("getOrganizationArchitecture")
    @POST
    @Operation(summary = "根据组织id获取所有管理员角色架构", tags = CUSTOM_SERVICE)
    public Set<ArchitectureCateEnum> getOrganizationArchitecture(RoleDto roleDto) {
        Assert.notEmpty(roleDto.getOrganization_id(), "组织id不能为空");
        // 通过组织id获取所有角色信息
        SingleResponse<BOList> roleBOList = BoServiceUtils.findListBySimple(ModelConst.T_ROLE, "organization_id", roleDto.getOrganization_id().get(0));
        if (!roleBOList.isSuccess()) {
            Exceptions.throwBizException(ErrorCodeEnum.BO_LIST_ERROR);
        }
        log.info("------------------------根据组织id获取所有角色列表：{}------------------------", JSONObject.toJSONString(roleBOList));

        Set<ArchitectureCateEnum> enums = Sets.newHashSet();
        Set<String> roleNameSet = roleBOList.getData().getData().stream().map(role -> String.valueOf(role.get("name"))).collect(Collectors.toSet());
        if (roleNameSet.contains("ROLE_VENDOR_ADMIN")) {
            enums.add(ArchitectureCateEnum.VENDOR);
        }
        if (roleNameSet.contains("ROLE_CUSTOMER_ADMIN")) {
            enums.add(ArchitectureCateEnum.CUSTOMER);
        }
        if (roleNameSet.contains("ROLE_PM_ADMIN")) {
            enums.add(ArchitectureCateEnum.PM);
        }
        return enums;

    }

    /**
     * 根据角色id列表获取角色名称
     *
     * @param roleDto 角色信息
     * @return 管理员角色集合
     */
    @Path("listRoleNames")
    @POST
    @Operation(summary = "根据角色id列表获取角色名称", tags = CUSTOM_SERVICE)
    public Set<String> listRoleNames(RoleDto roleDto) {
        Assert.notEmpty(roleDto.getIds(), "角色id不能为空");
        // 通过角色id获取角色列表
        SingleResponse<BOList> roleBOList = BoServiceUtils.findListByIn(ModelConst.T_ROLE, "id", roleDto.getIds());
        log.info("------------------------根据角色id列表获取角色列表：{}------------------------", JSONObject.toJSONString(roleBOList));
        return roleBOList.getData().getData().stream()
                .map(role -> String.valueOf(role.get("name")))
                .collect(Collectors.toSet());
    }

    /**
     * 通过资源id查询包含该资源的角色列表
     *
     * @param roleQuery 角色查询条件
     * @return 响应结果
     */
    @Path("getRoleListByResourceId")
    @POST
    @Operation(summary = "通过资源id查询包含该资源的角色列表", tags = CUSTOM_SERVICE)
    public SingleResponse<BOList> getRoleListByResourceId(@Parameter RoleQueryDto roleQuery) {
        Assert.notNull(roleQuery.getResourceId(), "资源id不能为空");
        BOList boList = new BOList();
        // 通过资源id查角色资源表
        SingleResponse<BOList> role_resource_boList = BoServiceUtils.findListBySimple(ModelConst.T_ROLE_RESOURCE, "resource", roleQuery.getResourceId());
        log.info("------------------------通过资源id查询角色资源列表：{}------------------------", JSONObject.toJSONString(role_resource_boList));
        if (!role_resource_boList.isSuccess()) {
            Exceptions.throwBizException(ErrorCodeEnum.BO_LIST_ERROR);
        }
        if (role_resource_boList.getData().getTotal() > 0) {
            List<Object> roleIDList = role_resource_boList.getData().getData()
                    .stream()
                    .map(map -> map.get("role_id"))
                    .collect(Collectors.toList());
            StringBuilder sql = new StringBuilder();
            Map<String, Object> parameter = Maps.newHashMap();
            sql.append("select r.* from \n");
            sql.append(JdbcTemplateUtils.getTableName(ModelConst.T_ROLE)).append(" as r\n");
            sql.append("where 1 = 1\n");
            // 角色id
            if (!StringUtils.isEmpty(roleQuery.getId())) {
                sql.append("and r.id = :id\n");
                parameter.put("id", roleQuery.getId());
            } else {
                sql.append("and r.id in (:ids)");
                parameter.put("ids", roleIDList);
            }
            // 角色名称
            if (!StringUtils.isEmpty(roleQuery.getName())) {
                sql.append("and r.name = :name\n");
                parameter.put("name", roleQuery.getName());
            }
            // 所属组织
            if (!CollectionUtils.isEmpty(roleQuery.getOrganization_id())) {
                sql.append("and CASE WHEN JSON_VALID( r.organization_id ) THEN JSON_UNQUOTE( r.organization_id -> '$.id' ) IN (:orgIds) ELSE NULL END\n");
                parameter.put("orgIds", roleQuery.getOrganization_id().stream().map(SelectorFormat::getId).collect(Collectors.toList()));
            }
            // 角色创建时间
            if (!CollectionUtils.isEmpty(roleQuery.getCreatedTime())) {
                sql.append("and r.createdTime BETWEEN :createdStartTime and :createdEndTime\n");
                parameter.put("createdStartTime", roleQuery.getCreatedTime().get(0));
                parameter.put("createdEndTime", roleQuery.getCreatedTime().get(1));
            }
            log.info("sql = {}, parameters = {}", sql, JSONObject.toJSONString(parameter));
            List<Map<String, Object>> result = jdbcTemplate.queryForList(sql.toString(), parameter);
            if (!CollectionUtils.isEmpty(result)) {
                // 对结果进行格式化
                BoResultFormat.resultFormat(result, ModelConst.T_ROLE, true);
                boList.setData(result);
            } else {
                boList.setData(Lists.newArrayList());
            }
        } else {
            boList.setData(Lists.newArrayList());
        }
        boList.setSchemaCode(ModelConst.T_ROLE);
        boList.setTotal(boList.getData().size());
        return SingleResponse.of(boList);
    }

    /**
     * 获取组织下所有角色列表
     *
     * @param saveOrUpdateBO 列表查询
     * @return 响应结果
     */
    @Path("getRoleListByOrgId")
    @POST
    @Operation(summary = "获取组织下所有角色列表", tags = CUSTOM_SERVICE)
    public SingleResponse<BOList> getRoleListByOrgId(@Parameter SaveOrUpdateBO saveOrUpdateBO) {
        // 获取查询条件
        Map<String, Object> param = saveOrUpdateBO.getData();
        Integer pageIndex = MapUtils.getInteger(param, "pageIndex");
        Integer pageSize = MapUtils.getInteger(param, "pageSize");
        String orgId = MapUtils.getString(param, "orgId");

        // 查询角色列表
        SingleResponse<BOList> roleBOList;
        String[] columns;
        Operator[] operators;
        Object[] columnsVal;
        if (StringUtils.isEmpty(orgId)) {
            columns = new String[]{"organization_id"};
            operators = new Operator[]{Operator.IS_NULL};
            columnsVal = new Object[]{null};
        } else {
            columns = new String[]{"organization_id", "organization_id"};
            operators = new Operator[]{Operator.EQ, Operator.IS_NULL};
            columnsVal = new Object[]{orgId, null};
        }
        roleBOList = BoServiceUtils.findListByOrAndLimit(ModelConst.T_ROLE, columns, columnsVal, operators, pageIndex, pageSize);
        log.info("------------------------获取指定组织下所有角色列表：{}------------------------", JSONObject.toJSONString(roleBOList));
        return roleBOList;
    }

    /**
     * 刷新资源
     *
     * @param resourceDto 资源
     */
    @Path("refreshResource")
    @POST
    @Operation(summary = "刷新资源", tags = CUSTOM_SERVICE)
    public SingleResponse<String> refreshResource(@Parameter ResourceDto resourceDto) {
        Assert.notNull(resourceDto.getAppCode(), "应用编码不能为空");
        String appCode = resourceDto.getAppCode();
        // fixme 只更新指定应用
        if (!(appCode.equals(AppConst.DEMAND_POOL) || appCode.equals(AppConst.SOURCING_CENTER) || appCode.equals(AppConst.COMMODITYMATERIALS)
                || appCode.equals(AppConst.ORDER_CENTER) || appCode.equals(AppConst.FINANCIALCENTER) || appCode.equals(AppConst.APPROVAL) || appCode.equals(AppConst.PERSONAL_CENTER)
                || appCode.equals(AppConst.OPERATION1_CENTER) || appCode.equals(AppConst.GM_MARKET) || appCode.equals(AppConst.SYSTEM_MANAGEMENT))) {
            return SingleResponse.of("No refresh required");
        }
        // 获取重新部署后的应用元数据
        SingleResponse<?> response = getMenuTree(appCode);

        // 通过应用编码和类型获取本地资源
        String[] columns = new String[]{"appCode", "type"};
        Operator[] operators = new Operator[]{Operator.EQ, Operator.EQ};
        Object[] columnsVal = new Object[]{appCode, ResourceTypeEnum.APP.getCode()};
        SingleResponse<BOList> appBOList = BoServiceUtils.findListByComplex(ModelConst.T_RESOURCE, columns, columnsVal, operators);
        log.info("----------通过应用编码和类型获取资源数据：{}----------", JSONObject.toJSONString(appBOList));

        // 应用第一次发布，新增资源
        if (appBOList.getData().getTotal() == 0) {
            // 获取sort最大值
            BigDecimal sort = Objects.requireNonNull(JdbcTemplateUtils.builder(ModelConst.T_RESOURCE)
                    .selectField("MAX(sort)"))
                    .queryForObject(BigDecimal.class);
            if (sort == null) {
                sort = BigDecimal.ONE;
            }
            createResource(response.getData(), sort.intValue() + 1);
        } else {
            // 获取应用之前的资源id和资源顺序
            String appId = String.valueOf(appBOList.getData().getData().get(0).get("id"));
            Integer appSort = ((BigDecimal) appBOList.getData().getData().get(0).get("sort")).intValue();

            List<Map<String, Object>> resourceDataList = Lists.newArrayList();
            List<String> bizObjectIds = Lists.newArrayList();
            SingleResponse<BOList> oldMenusList;
            SingleResponse<BOList> oldTabsList;
            SingleResponse<BOList> oldButtonsList;

            // 重新部署后的元数据信息
            List<Map<String, Object>> appDataList = TypeReferenceUtils.readValueToList(JSONObject.toJSONString(response.getData()));
            log.info("----------appDataList：{}----------", JSONObject.toJSONString(appDataList));
            Map<String, Object> appDataMap = appDataList.get(0);

            // 重新部署后的菜单信息
            List<Map<String, Object>> newMenusList = TypeReferenceUtils.readValueToList(JSONObject.toJSONString(appDataMap.get("appMenuItems")));
            newMenusList = newMenusList.stream()
                    // 获取的资源树包含FOLDER和PAGE，只取类型为PAGE的数据
                    .filter(appMenuItemMap -> "PAGE".equals(appMenuItemMap.get("menuItemType")) || "URL".equals(appMenuItemMap.get("menuItemType")))
                    .collect(Collectors.toList());
            log.info("----------newMenusList：{}----------", JSONObject.toJSONString(newMenusList));

            // 获取应用本地菜单数据
            columns = new String[]{"appCode", "type"};
            operators = new Operator[]{Operator.EQ, Operator.EQ};
            columnsVal = new Object[]{appCode, ResourceTypeEnum.MENU.getCode()};
            oldMenusList = BoServiceUtils.findListByComplex(ModelConst.T_RESOURCE, columns, columnsVal, operators);

            // 重新部署后的菜单id列表
            List<String> newMenusItemCodeList = newMenusList.stream().map(newMenuMap -> String.valueOf(newMenuMap.get("menuItemCode"))).collect(Collectors.toList());
            // 本地菜单id列表
            List<String> oldMenusItemCodeList = oldMenusList.getData().getData().stream().map(oldMenuMap -> String.valueOf(oldMenuMap.get("menuItemCode"))).collect(Collectors.toList());

            // 需要删除的菜单数据
            if (oldMenusList.getData().getTotal() > 0) {
                for (Map<String, Object> oldMenuMap : oldMenusList.getData().getData()) {
                    String oldMenuItemCode = String.valueOf(oldMenuMap.get("menuItemCode"));
                    if (!newMenusItemCodeList.contains(oldMenuItemCode)) {
                        bizObjectIds.add(String.valueOf(oldMenuMap.get("id")));
                    }
                }
            }

            for (Map<String, Object> appMenuDataMap : newMenusList) {
                String appMenuId;
                if (!oldMenusItemCodeList.contains(String.valueOf(appMenuDataMap.get("menuItemCode")))) {
                    Map<String, Object> appMenuMap = Maps.newHashMap();
                    appMenuId = SchemaHelper.getId();
                    appMenuMap.put("id", appMenuId);
                    appMenuMap.put("parent_id", appId);
                    appMenuMap.put("type", ResourceTypeEnum.MENU.getCode());
                    appMenuMap.put("name", appMenuDataMap.get("menuItemName"));
                    appMenuMap.put("level", ResourceTypeEnum.MENU.ordinal());
                    appMenuMap.put("sort", appSort);
                    appMenuMap.put("sortKey", appMenuDataMap.get("sortKey"));
                    appMenuMap.put("appCode", appDataMap.get("appCode"));
                    appMenuMap.put("menuCode", appMenuDataMap.get("menuCode"));
                    appMenuMap.put("menuItemCode", appMenuDataMap.get("menuItemCode"));
                    appMenuMap.put("componentCode", null);
                    appMenuMap.put("groupCode", null);
                    appMenuMap.put("pageCode", null);
                    appMenuMap.put("leaf", false);
                    resourceDataList.add(appMenuMap);
                } else {
                    appMenuId = String.valueOf(oldMenusList.getData().getData()
                            .stream()
                            .filter(oldMenuMap -> MapUtils.getString(oldMenuMap, "menuItemCode").equals(MapUtils.getString(appMenuDataMap, "menuItemCode")))
                            .collect(Collectors.toList()).get(0).get("id"));
                }

                if (appMenuDataMap.get("TabsPanelContainers") == null) {
                    continue;
                }
                // 重新部署后的标签页信息
                List<Map<String, Object>> appTabsPanelList = TypeReferenceUtils.readValueToList(JSONObject.toJSONString(appMenuDataMap.get("TabsPanelContainers")));
                log.info("----------appTabsPanelList：{}----------", JSONObject.toJSONString(appTabsPanelList));

                // 获取应用本地标签页数据
                columns = new String[]{"appCode", "type", "pageCode"};
                operators = new Operator[]{Operator.EQ, Operator.EQ, Operator.EQ};
                columnsVal = new Object[]{appCode, ResourceTypeEnum.TABS.getCode(), appMenuDataMap.get("pageCode")};
                oldTabsList = BoServiceUtils.findListByComplex(ModelConst.T_RESOURCE, columns, columnsVal, operators);

                // 重新部署后的标签页id列表
                List<String> newTabsComponentCodeList = appTabsPanelList.stream().map(newTab -> String.valueOf(newTab.get("id"))).collect(Collectors.toList());
                // 本地标签页id列表
                List<String> oldTabsComponentCodeList = oldTabsList.getData().getData().stream().map(oldTab -> String.valueOf(oldTab.get("componentCode"))).collect(Collectors.toList());

                // 需要删除的标签页数据
                if (oldTabsList.getData().getTotal() > 0) {
                    for (Map<String, Object> oldTabsMap : oldTabsList.getData().getData()) {
                        String oldTabsComponentCode = String.valueOf(oldTabsMap.get("componentCode"));
                        if (!newTabsComponentCodeList.contains(oldTabsComponentCode)) {
                            bizObjectIds.add(String.valueOf(oldTabsMap.get("id")));
                        }
                    }
                }

                for (Map<String, Object> appTabsPanelDataMap : appTabsPanelList) {
                    String tabsPanelId;
                    if (!oldTabsComponentCodeList.contains(String.valueOf(appTabsPanelDataMap.get("id")))) {
                        Map<String, Object> appTabsPanelMap = Maps.newHashMap();
                        tabsPanelId = SchemaHelper.getId();
                        appTabsPanelMap.put("id", tabsPanelId);
                        appTabsPanelMap.put("parent_id", appMenuId);
                        appTabsPanelMap.put("type", ResourceTypeEnum.TABS.getCode());
                        // 获取标签页名称
                        Map<String, Object> propsMap = JSONObject.parseObject(JSONObject.toJSONString(appTabsPanelDataMap.get("props")));
                        appTabsPanelMap.put("name", propsMap.get("tab"));
                        appTabsPanelMap.put("level", ResourceTypeEnum.TABS.ordinal());
                        appTabsPanelMap.put("sort", appSort);
                        appTabsPanelMap.put("sortKey", 0);
                        appTabsPanelMap.put("appCode", appDataMap.get("appCode"));
                        appTabsPanelMap.put("componentCode", appTabsPanelDataMap.get("id"));
                        appTabsPanelMap.put("groupCode", appMenuDataMap.get("groupCode"));
                        appTabsPanelMap.put("pageCode", appMenuDataMap.get("pageCode"));
                        appTabsPanelMap.put("leaf", false);
                        resourceDataList.add(appTabsPanelMap);
                    } else {
                        tabsPanelId = String.valueOf(oldTabsList.getData().getData()
                                .stream()
                                .filter(oldTabsMap -> MapUtils.getString(oldTabsMap, "componentCode").equals(MapUtils.getString(appTabsPanelDataMap, "id")))
                                .collect(Collectors.toList()).get(0).get("id"));
                    }

                    if (appTabsPanelDataMap.get("Buttons") == null) {
                        continue;
                    }

                    // 重新部署后的按钮信息
                    List<Map<String, Object>> appButtonList = TypeReferenceUtils.readValueToList(JSONObject.toJSONString(appTabsPanelDataMap.get("Buttons")));
                    log.info("----------appButtonList：{}----------", JSONObject.toJSONString(appButtonList));

                    // 获取应用本地按钮数据
                    columns = new String[]{"appCode", "type", "pageCode", "parent_id"};
                    operators = new Operator[]{Operator.EQ, Operator.EQ, Operator.EQ, Operator.EQ};
                    columnsVal = new Object[]{appCode, ResourceTypeEnum.BUTTON.getCode(), appMenuDataMap.get("pageCode"), tabsPanelId};
                    oldButtonsList = BoServiceUtils.findListByComplex(ModelConst.T_RESOURCE, columns, columnsVal, operators);

                    // 重新部署后的按钮id列表
                    List<String> newButtonsComponentCodeList = appButtonList.stream().map(newButton -> String.valueOf(newButton.get("id"))).collect(Collectors.toList());
                    // 本地按钮id列表
                    List<String> oldButtonsComponentCodeList = oldButtonsList.getData().getData().stream().map(oldButton -> String.valueOf(oldButton.get("componentCode"))).collect(Collectors.toList());

                    // 需要删除的按钮数据
                    if (oldButtonsList.getData().getTotal() > 0) {
                        for (Map<String, Object> oldButtonMap : oldButtonsList.getData().getData()) {
                            String oldTabsComponentCode = String.valueOf(oldButtonMap.get("componentCode"));
                            if (!newButtonsComponentCodeList.contains(oldTabsComponentCode)) {
                                bizObjectIds.add(String.valueOf(oldButtonMap.get("id")));
                            }
                        }
                    }

                    for (Map<String, Object> appButtonDataMap : appButtonList) {
                        if (!oldButtonsComponentCodeList.contains(String.valueOf(appButtonDataMap.get("id")))) {
                            Map<String, Object> appButtonMap = Maps.newHashMap();
                            String buttonId = SchemaHelper.getId();
                            appButtonMap.put("id", buttonId);
                            appButtonMap.put("parent_id", tabsPanelId);
                            appButtonMap.put("type", ResourceTypeEnum.BUTTON.getCode());
                            appButtonMap.put("level", ResourceTypeEnum.BUTTON.ordinal());
                            appButtonMap.put("name", appButtonDataMap.get("name"));
                            appButtonMap.put("sort", appSort);
                            appButtonMap.put("sortKey", 0);
                            appButtonMap.put("appCode", appDataMap.get("appCode"));
                            appButtonMap.put("componentCode", appButtonDataMap.get("id"));
                            appButtonMap.put("groupCode", appMenuDataMap.get("groupCode"));
                            appButtonMap.put("pageCode", appMenuDataMap.get("pageCode"));
                            appButtonMap.put("leaf", true);
                            resourceDataList.add(appButtonMap);
                        }
                    }
                }
            }
            if (!CollectionUtils.isEmpty(bizObjectIds)) {
                log.info("--------bizObjectIds：{}-------", JSONObject.toJSONString(resourceDataList));
                BoServiceUtils.batchDeleteBO(ModelConst.T_RESOURCE, bizObjectIds, true);
            }
            if (!CollectionUtils.isEmpty(resourceDataList)) {
                log.info("--------resourceDataList：{}-------", JSONObject.toJSONString(resourceDataList));
                BoServiceUtils.createBo(ModelConst.T_RESOURCE, resourceDataList);
            }
        }
        resourceList.forEach(this::handleResource);
        return SingleResponse.of("Refresh resource succeeded");
    }

    /**
     * 创建角色资源表数据
     *
     * @param roleId       角色id
     * @param resourceList 资源列表
     */
    private void createRoleResource(String roleId, List<ResourceDto> resourceList) {
        // 角色资源表中插入数据
        List<Map<String, Object>> roleResourceList = Lists.newArrayList();
        resourceList.forEach(resourceDto -> {
            Map<String, Object> roleResourceMap = Maps.newHashMap();
            roleResourceMap.put("role_id", roleId);
            roleResourceMap.put("resource", resourceDto.getId());
            roleResourceList.add(roleResourceMap);
        });
        log.info("------------------------创建角色资源中间表数据：{}------------------------", JSONObject.toJSONString(roleResourceList));
        BoServiceUtils.createBo(ModelConst.T_ROLE_RESOURCE, roleResourceList);
    }

    /**
     * 根据父菜单获取所有子菜单
     *
     * @param parentId 父菜单id
     * @return 子菜单合集
     */
    private List<ResourceTree> getResourceByParentId(String parentId) {
        List<ResourceTree> childrenList = Lists.newArrayList();
        String[] columns = new String[]{"enabled", "parent_id"};
        Operator[] operators = new Operator[]{Operator.EQ, Operator.EQ};
        Object[] columnsVal = new Object[]{"1", parentId};
        SingleResponse<BOList> childrenResultList = BoServiceUtils.findListByComplex(ModelConst.T_RESOURCE, columns, columnsVal, operators);
        if (!childrenResultList.isSuccess() || childrenResultList.getData() == null) {
            Exceptions.throwBizException(ErrorCodeEnum.BO_LIST_ERROR);
        }
        boolean leaf;
        if (childrenResultList.getData().getTotal() == 0) {
            leaf = true;
        } else {
            leaf = new Integer(1).equals(childrenResultList.getData().getData().get(0).get("leaf"));
        }

        for (Map<String, Object> childMap : childrenResultList.getData().getData()) {
            JSONObject keyJSON = new JSONObject();
            keyJSON.put("id", childMap.get("id"));
            keyJSON.put("parent_id", childMap.get("parent_id"));
            keyJSON.put("name", childMap.get("name"));
            keyJSON.put("type", childMap.get("type"));
            keyJSON.put("level", ((BigDecimal) childMap.get("level")).intValue());
            keyJSON.put("sort", ((BigDecimal) childMap.get("sort")).intValue());
            keyJSON.put("appCode", childMap.get("appCode"));
            keyJSON.put("permId", childMap.get("permId"));
            keyJSON.put("menuCode", childMap.get("menuCode"));
            keyJSON.put("groupCode", childMap.get("groupCode"));
            keyJSON.put("menuItemCode", childMap.get("menuItemCode"));
            keyJSON.put("componentCode", childMap.get("componentCode"));
            keyJSON.put("pageCode", childMap.get("pageCode"));
            ResourceTree childResource = ResourceTree.builder().build();
            childResource.setKey(keyJSON.toJSONString());
            childResource.setTitle(String.valueOf(childMap.get("name")));
            if (!leaf) {
                childResource.setChildren(getResourceByParentId(String.valueOf(childMap.get("id"))));
            }
            childrenList.add(childResource);
        }
        return childrenList;
    }

    /**
     * 添加应用角色组
     *
     * @param role 角色信息
     * @return 应用角色组集合
     */
    private List<PermGroupDto> addPermGroup(RoleDto role) {
        List<SubjectDto> subjectDtoList = Lists.newArrayList();
        // fixme 2021.08.25默认改为按人员授权。授权方式：1按组织，2按人员，3按标签。2021.10.18增加判断，根据授权方式来确定是按人员授权或是按标签授权
        if ("3".equals(role.getAuthType())) {
            // 按标签授权，使用页面选择的角色管理范围
            List<String> tagScopeIdList = Arrays.asList(role.getTag_scope().split(","));
            SingleResponse<BOList> tabScopeBOList = BoServiceUtils.findListByIn(ModelConst.T_TAG_SCOPE, "id", tagScopeIdList);
            if (!tabScopeBOList.isSuccess()) {
                throw new BizException(ErrorCodeEnum.BO_GET_ERROR.getErrDesc());
            }
            tabScopeBOList.getData().getData().forEach(tabScope -> {
                SubjectDto subjectDto = new SubjectDto();
                subjectDto.setId(String.valueOf(tabScope.get("tag_id")));
                subjectDto.setName(String.valueOf(tabScope.get("tag_name")));
                subjectDtoList.add(subjectDto);
            });
        } else if ("2".equals(role.getAuthType())) {
            SubjectDto subjectDto = new SubjectDto();
            // fixme 授权范围不能为空，默认给管理员。后续用户选择角色时添加用户
            subjectDto.setId(DEFAULT_ID);
            subjectDto.setName(DEFAULT_NAME);
            subjectDtoList.add(subjectDto);
        }
        List<PermGroupDto> permGroupDtoList = Lists.newArrayList();

        // 根据应用名称进行分组
        Map<String, List<ResourceDto>> resourceMap = role.getResourceList().stream().collect(Collectors.groupingBy(ResourceDto::getAppCode));
        Set<String> keySet = resourceMap.keySet();
        String PermGroupId;

        // 设置角色名称
        String roleName = !CollectionUtils.isEmpty(role.getOrganization_id()) ? role.getOrganization_name().concat("-").concat(role.getName()) : role.getName();

        PermGroupDto source = PermGroupDto.builder()
                .name(roleName)
                .subjectDtoList(subjectDtoList)
                .authType(Integer.parseInt(role.getAuthType()))
                .build();
        for (String key : keySet) {
            PermGroupDto target = new PermGroupDto();
            BeanUtils.copyProperties(source, target);
            PermGroupId = UUID.randomUUID().toString().replaceAll("-", "");
            target.setPermGroupId(PermGroupId);
            target.setAppCode(key);
            permGroupDtoList.add(target);
        }

        // 如果没有勾选系统管理，需要在此处自动添加，不然会导致用户看不到菜单
        if (!keySet.contains(AppConst.SYSTEM_MANAGEMENT)) {
            PermGroupDto target = new PermGroupDto();
            BeanUtils.copyProperties(source, target);
            PermGroupId = UUID.randomUUID().toString().replaceAll("-", "");
            target.setPermGroupId(PermGroupId);
            target.setAppCode(AppConst.SYSTEM_MANAGEMENT);
            permGroupDtoList.add(target);
        }
        log.info("------------------------添加应用角色组请求参数：{}------------------------", JSONObject.toJSONString(permGroupDtoList));
        SingleResponse<?> permGroupResponse = this.permService.addPermGroup(PermExtGroupDto.builder().permGroupDtos(permGroupDtoList).build());
        Assert.isTrue(permGroupResponse.isSuccess(), permGroupResponse.getErrMessage());
        return permGroupDtoList;
    }

    /**
     * 修改应用角色组
     *
     * @param role 角色信息
     * @return 应用角色组集合
     */
    private List<PermGroupDto> updatePermGroup(RoleDto role) {
        List<SubjectDto> subjectDtoList = Lists.newArrayList();
        if ("3".equals(role.getAuthType())) {
            // 按标签授权，使用页面选择的角色管理范围
            List<String> tagScopeIdList = Arrays.asList(role.getTag_scope().split(","));
            SingleResponse<BOList> tabScopeBOList = BoServiceUtils.findListByIn(ModelConst.T_TAG_SCOPE, "id", tagScopeIdList);
            if (!tabScopeBOList.isSuccess()) {
                throw new BizException(ErrorCodeEnum.BO_LIST_ERROR.getErrDesc());
            }
            tabScopeBOList.getData().getData().forEach(tabScope -> {
                SubjectDto subjectDto = new SubjectDto();
                subjectDto.setId(String.valueOf(tabScope.get("tag_id")));
                subjectDto.setName(String.valueOf(tabScope.get("tag_name")));
                subjectDtoList.add(subjectDto);
            });
        } else if ("2".equals(role.getAuthType())) {
            // 获取之前的人员范围
            SingleResponse<BOList> rolePermBOList = BoServiceUtils.findListBySimple(ModelConst.T_ROLE_PERM, "role_id", role.getId());
            String groupId = String.valueOf(rolePermBOList.getData().getData().get(0).get("group_id"));
            SingleResponse<?> response = this.permService.queryPermGroupByPermGroupId(groupId);
            PermGroupDto permGroupDto = ObjectMapperUtils.fromJSON(ObjectMapperUtils.toJSONString(response.getData()), PermGroupDto.class);
            subjectDtoList.addAll(permGroupDto.getSubjectDtoList());
        }
        List<PermGroupDto> permGroupDtoList = Lists.newArrayList();

        // 根据应用名称进行分组
        Map<String, List<ResourceDto>> resourceMap = role.getResourceList().stream().collect(Collectors.groupingBy(ResourceDto::getAppCode));
        Set<String> keySet = resourceMap.keySet();
        String permGroupId;

        // 设置角色名称
        String roleName = !CollectionUtils.isEmpty(role.getOrganization_id()) ? role.getOrganization_name().concat("-").concat(role.getName()) : role.getName();
        SingleResponse<BOList> rolePermBOList;
        PermGroupDto permGroupDto;
        SingleResponse<?> permGroupResponse;

        for (String key : keySet) {
            // 获取角色权限组id
            String[] columnNames = new String[]{"role_id", "app_code"};
            Operator[] operators = new Operator[]{Operator.EQ, Operator.EQ};
            Object[] columnValues = new Object[]{role.getId(), key};
            rolePermBOList = BoServiceUtils.findListByComplex(ModelConst.T_ROLE_PERM, columnNames, columnValues, operators);
            // 角色组存在时，查询角色组权限信息
            if (rolePermBOList.getData().getTotal() > 0) {
                permGroupId = String.valueOf(rolePermBOList.getData().getData().get(0).get("group_id"));
                // 根据角色组id获取角色组信息
                SingleResponse<?> response = this.permService.queryPermGroupByPermGroupId(permGroupId);
                log.info("------------------------根据角色组id获取角色组权限信息：{}------------------------", JSONObject.toJSONString(response));
                permGroupDto = ObjectMapperUtils.fromJSON(ObjectMapperUtils.toJSONString(response.getData()), PermGroupDto.class);

                // 修改角色组名称
                permGroupDto.setName(roleName);

                // 如果是按标签授权，修改授权范围
                if ("3".equals(role.getAuthType())) {
                    permGroupDto.setSubjectDtoList(subjectDtoList);
                }
                log.info("------------------------修改应用角色组请求参数：{}------------------------", JSONObject.toJSONString(permGroupDto));
                permGroupResponse = this.permService.updatePermGroupByPermGroupId(Collections.singletonList(permGroupDto));
            } else {
                permGroupDto = new PermGroupDto();
                permGroupId = UUID.randomUUID().toString().replaceAll("-", "");
                permGroupDto.setPermGroupId(permGroupId);
                permGroupDto.setName(roleName);
                permGroupDto.setSubjectDtoList(subjectDtoList);
                permGroupDto.setAuthType(Integer.parseInt(role.getAuthType()));
                permGroupDto.setAppCode(key);
                log.info("------------------------添加应用角色组请求参数：{}------------------------", JSONObject.toJSONString(permGroupDto));
                permGroupResponse = this.permService.addPermGroup(PermExtGroupDto.builder().permGroupDtos(Collections.singletonList(permGroupDto)).build());
            }
            if (!permGroupResponse.isSuccess()) {
                Exceptions.throwBizException(new BizException(permGroupResponse.getErrCode(), permGroupResponse.getErrMessage(), permGroupResponse.getCorrectGuid()));
            }
            permGroupDtoList.add(permGroupDto);
        }
        return permGroupDtoList;
    }

    /**
     * 设置角色选人控件冗余名称
     *
     * @param role 角色信息
     */
    private void setRoleValue(RoleDto role) {
        if (!CollectionUtils.isEmpty(role.getOrganization_id())) {
            role.setOrganization_name(role.getOrganization_id().get(0).getName());
        } else {
            role.setOrganization_name("");
        }
    }

    /**
     * 判断当前角色是否存在
     *
     * @param roleId           角色id
     * @param roleName         角色名称
     * @param organizationName 组织名称
     */
    private void checkRoleName(String roleId, String roleName, String organizationName) {
        String[] columnNames = new String[]{"name", "organization_name"};
        Operator[] operators = new Operator[]{Operator.EQ, Operator.EQ};
        Object[] columnValues = new Object[]{roleName, organizationName};
        SingleResponse<BOList> roleBOList = BoServiceUtils.findListByComplex(ModelConst.T_ROLE, columnNames, columnValues, operators);
        // id不为空，修改角色
        if (!StringUtils.isEmpty(roleId)) {
            if (roleBOList.getData().getTotal() > 0) {
                Assert.isTrue(roleId.equals(roleBOList.getData().getData().get(0).get("id")), "角色已存在");
            }
        } else {
            Assert.isTrue(roleBOList.getData().getTotal() == 0, "角色已存在");
        }
    }

    /**
     * 更新角色组领域模型权限
     *
     * @param appCode      应用编码
     * @param permGroupId  权限组id
     * @param roleId       系统管理就角色id
     * @param rowType      数据查看范围
     * @param roleTypeName 角色类型名称
     */
    private void updateAppDomain(String appCode, String permGroupId, String roleId, String rowType, String roleTypeName) {
        // 获取应用下所有领域模型权限信息
        SingleResponse<?> appPage = getAppDomain(appCode);
        AppAllInOne AppAllInOne = ObjectMapperUtils.fromJSON(ObjectMapperUtils.toJSONString(appPage.getData()), AppAllInOne.class);

        // 设置数据模型基础服务操作权限，默认都给INSERT、UPDATE、DELETE
        List<ModelDataOperatDto> modelDataOperatorDtoList = setModelDataOperator();

        // 设置领域模型属性值
        PermDomainDto permDomainDto = new PermDomainDto();
        permDomainDto.setAppCode(appCode);
        permDomainDto.setPermGroupId(permGroupId);
        List<PermDomainDataServiceDto> permDomainDataServiceDtoList = Lists.newArrayList();

        AppAllInOne.getGroupVOS().forEach(groupVO -> groupVO.getDomainModels().forEach(domainModel -> {
            PermDomainDataServiceDto permDomainDataServiceDto = new PermDomainDataServiceDto();

            // 获取领域模型编码，使用domainModel.getMainSchema()获取的不正确，改用domainModel.getCode()
            String domainCode = domainModel.getCode();
            permDomainDataServiceDto.setDomainCode(domainCode);

            // 获取角色领域模型权限
            String[] columnNames = new String[]{"app_code", "group_id", "domain_code", "perm_id"};
            Operator[] operators = new Operator[]{Operator.EQ, Operator.EQ, Operator.EQ, Operator.IS_NULL};
            Object[] columnValues = new Object[]{appCode, permGroupId, domainCode, null};
            SingleResponse<BOList> rolePermByComplex = BoServiceUtils.findListByComplex(ModelConst.T_ROLE_PERM, columnNames, columnValues, operators);
            log.info("------------------------通过应用编码、角色组id获取角色权限列表：{}------------------------", JSONObject.toJSONString(rolePermByComplex));
            String permDomainId;

            // 角色权限表中存在数据，使用之前的权限id
            if (rolePermByComplex.getData().getTotal() > 0) {
                permDomainId = String.valueOf(rolePermByComplex.getData().getData().get(0).get("perm_domain_id"));
            } else {
                permDomainId = UUID.randomUUID().toString().replaceAll("-", "");
                createRolePermByDomain(permDomainDto, roleId, permDomainId, domainCode);
            }
            permDomainDataServiceDto.setPermDomainId(permDomainId);

            // 设置数据模型集合
            Map<String, ModelDataDto> modelDataDtoMap = Maps.newHashMap();
            for (BizSchema bizSchema : domainModel.getBizSchemas()) {
                ModelDataDto modelDataDto = new ModelDataDto();
                // 设置模型高级权限规则，默认为空
                modelDataDto.setModelDataHighDtoList(Lists.newArrayList());

                // 设置行权限
                ModelDataRowDto modelDataRowDto = new ModelDataRowDto();

                // fixme 资源表、角色资源表、角色权限、标签管理范围、组织属性给所有权限，避免获取菜单和标签时报错
                if (ModelConst.T_RESOURCE.equals(bizSchema.getCode()) || ModelConst.T_ROLE_RESOURCE.equals(bizSchema.getCode())
                        || ModelConst.T_ROLE_PERM.equals(bizSchema.getCode()) || ModelConst.T_ORGANIZATION_ATTRIBUTE.equals(bizSchema.getCode())) {
                    modelDataRowDto.setRowType(1);
                } else if (PlatformConst.VENDOR_ROLE.equals(roleTypeName) && (ModelConst.T_INQUIRY.equals(bizSchema.getCode()) || ModelConst.T_INQUIRY_GOODS.equals(bizSchema.getCode())
                        || ModelConst.T_INQUIRY_GOODS_CLARIFY.equals(bizSchema.getCode()) || ModelConst.INQUIRY_GOODS.equals(bizSchema.getCode()))) {
                    // fixme 如果角色供应商，可以看到所有询价信息。询价表、询价商品表、澄清记录表给所有权限
                    modelDataRowDto.setRowType(1);
                } else {
                    if (RowTypeEnum.ONLY_ONESELF.getCode().equals(rowType)) {
                        // 仅自己可见
                        modelDataRowDto.setRowType(4);
                    } else if (RowTypeEnum.DEPARTMENT.getCode().equals(rowType)) {
                        // 本部门可见
                        modelDataRowDto.setRowType(3);
                    } else if (RowTypeEnum.ORGANIZATION.getCode().equals(rowType)) {
                        // todo 组织内可见，产品还未实现，先设置为全部可见
                        modelDataRowDto.setRowType(1);
                    } else if (RowTypeEnum.PARENT_ORGANIZATION.getCode().equals(rowType)) {
                        // todo 组织内可见，产品还未实现，先设置为全部可见
                        modelDataRowDto.setRowType(1);
                    } else if (RowTypeEnum.PM_MANAGER.getCode().equals(rowType)) {
                        // 全部可见
                        modelDataRowDto.setRowType(1);
                    } else if (RowTypeEnum.ROLE.getCode().equals(rowType)) {
                        // 标签管理范围
                        modelDataRowDto.setRowType(2);
                    } else if (RowTypeEnum.SCOPE.getCode().equals(rowType)) {
                        // 标签管理范围
                        modelDataRowDto.setRowType(2);
                    }
                }
                modelDataDto.setModelDataRowDto(modelDataRowDto);

                // 设置模型操作权限
                modelDataDto.setModelDataOperatDtoList(modelDataOperatorDtoList);

                // 设置列权限
                List<ModelDataColDto> modelDataColDtoList = Lists.newArrayList();
                bizSchema.getProperties().forEach(properties -> {
                    ModelDataColDto modelDataColDto = new ModelDataColDto();
                    modelDataColDto.setColName(properties.getCode());
                    // 1可见--不可写，2不可见--可写，3可见--可写，不可见--不可写则不传参数。默认给可见可写权限
                    modelDataColDto.setPerm(3);
                    modelDataColDtoList.add(modelDataColDto);
                });
                modelDataDto.setModelDataColDtoList(modelDataColDtoList);
                modelDataDtoMap.put(bizSchema.getCode(), modelDataDto);
            }
            permDomainDataServiceDto.setModelDataDtoMap(modelDataDtoMap);
            permDomainDataServiceDtoList.add(permDomainDataServiceDto);
        }));
        permDomainDto.setPermDomainDataServiceDtoList(permDomainDataServiceDtoList);
        log.info("------------------------更新角色组领域模型权限，领域模型资源数据：{}------------------------", JSONObject.toJSONString(permDomainDto));
        SingleResponse<?> singleResponse = this.permService.updateAppDomainAll(permDomainDto);
        if (!singleResponse.isSuccess()) {
            Exceptions.throwBizException(new BizException(singleResponse.getErrCode(), singleResponse.getErrMessage(), singleResponse.getCorrectGuid()));
        }
    }

    /**
     * 设置数据模型基础服务操作权限
     *
     * @return 操作权限列表
     */
    private List<ModelDataOperatDto> setModelDataOperator() {
        List<ModelDataOperatDto> modelDataOperatorDtoList = Lists.newArrayList();

        // 设置新增权限
        ModelDataOperatDto insertOperator = new ModelDataOperatDto();
        insertOperator.setTriggerType("INSERT");
        modelDataOperatorDtoList.add(insertOperator);

        // 设置更新权限
        ModelDataOperatDto updateOperator = new ModelDataOperatDto();
        updateOperator.setTriggerType("UPDATE");
        modelDataOperatorDtoList.add(updateOperator);

        // 设置删除权限
        ModelDataOperatDto deleteOperator = new ModelDataOperatDto();
        deleteOperator.setTriggerType("DELETE");
        modelDataOperatorDtoList.add(deleteOperator);
        return modelDataOperatorDtoList;
    }

    /**
     * 更新角色组菜单权限
     *
     * @param appResourceList 应用资源列表
     * @param permGroupId     权限组id
     * @param roleId          系统管理角色id
     */
    private void updateAppMenu(List<ResourceDto> appResourceList, String permGroupId, String roleId) {
        // 获取资源类型为菜单的数据
        List<ResourceDto> menuResourceList = appResourceList.stream().filter(resource -> ResourceTypeEnum.MENU.getCode().equals(resource.getType())).collect(Collectors.toList());
        if (menuResourceList.size() == 0) {
            return;
        }

        // 根据menuCode进行分组
        Map<String, List<ResourceDto>> menuMapAfterGroupBy = menuResourceList.stream().collect(Collectors.groupingBy(ResourceDto::getMenuCode));
        Set<String> menuKeySet = menuMapAfterGroupBy.keySet();

        // 设置角色权限
        PermFeatureMenuDto permFeatureMenuDto = new PermFeatureMenuDto();
        permFeatureMenuDto.setAppCode(menuResourceList.get(0).getAppCode());
        permFeatureMenuDto.setPermGroupId(permGroupId);
        String permId;// 权限id

        // 获取角色菜单权限
        String[] columnNames = new String[]{"app_code", "group_id", "group_code", "perm_domain_id"};
        Operator[] operators = new Operator[]{Operator.EQ, Operator.EQ, Operator.IS_NULL, Operator.IS_NULL};
        Object[] columnValues = new Object[]{permFeatureMenuDto.getAppCode(), permFeatureMenuDto.getPermGroupId(), null, null};
        SingleResponse<BOList> rolePermByComplex = BoServiceUtils.findListByComplex(ModelConst.T_ROLE_PERM, columnNames, columnValues, operators);
        log.info("------------------------通过应用编码、角色组id获取角色权限列表：{}------------------------", JSONObject.toJSONString(rolePermByComplex));

        // 角色权限表中存在数据，使用之前的权限id
        if (rolePermByComplex.getData().getTotal() > 0) {
            permId = String.valueOf(rolePermByComplex.getData().getData().get(0).get("perm_id"));
        } else {
            permId = UUID.randomUUID().toString().replaceAll("-", "");
            createRolePermByMenu(permFeatureMenuDto, roleId, permId);
        }
        permFeatureMenuDto.setPermId(permId);

        // 设置菜单组对应的菜单项编码集合
        Map<String, List<String>> menuBarItemsMap = Maps.newHashMap();
        List<ResourceDto> menuList;
        List<String> menuItemCodeList;
        for (String menuKey : menuKeySet) {
            // 获取菜单项编码
            menuList = menuMapAfterGroupBy.get(menuKey);
            menuItemCodeList = Lists.newArrayList();
            for (ResourceDto menu : menuList) {
                menuItemCodeList.add(menu.getMenuItemCode());
            }
            menuBarItemsMap.put(menuList.get(0).getMenuCode(), menuItemCodeList);
        }
        permFeatureMenuDto.setMenuBarItemsMap(menuBarItemsMap);

        log.info("------------------------更新角色组菜单权限，菜单资源数据：{}------------------------", JSONObject.toJSONString(permFeatureMenuDto));
        SingleResponse<?> singleResponse = this.permService.updateAppMenuAll(permFeatureMenuDto);
        if (!singleResponse.isSuccess()) {
            Exceptions.throwBizException(new BizException(singleResponse.getErrCode(), singleResponse.getErrMessage(), singleResponse.getCorrectGuid()));
        }
    }

    /**
     * 更新角色组页面权限
     *
     * @param appResourceList 应用资源列表
     * @param permGroupId     权限组id
     * @param roleId          系统管理角色id
     */
    private void updateAppPage(List<ResourceDto> appResourceList, String permGroupId, String roleId) {
        // 获取资源类型为页签的数据
        List<ResourceDto> tabResourceList = appResourceList.stream().filter(resourceDto -> ResourceTypeEnum.TABS.getCode().equals(resourceDto.getType())).collect(Collectors.toList());
        if (tabResourceList.size() == 0) {
            return;
        }

        // 获取应用下的页面数据，给所有页面开放权限
        SingleResponse<?> appPage = getAppPage(tabResourceList.get(0).getAppCode());
        AppAllInOne AppAllInOne = ObjectMapperUtils.fromJSON(ObjectMapperUtils.toJSONString(appPage.getData()), AppAllInOne.class);

        // 当前分组下的页面列表
        List<Page> pages;

        // 根据groupCode循环调用更新页面权限接口
        for (AppAllInOne.GroupVO groupVO : AppAllInOne.getGroupVOS()) {
            // 设置页面权限
            PermFeaturePageDto permFeaturePageDto = new PermFeaturePageDto();
            List<PageGroupDto> pageGroupList = Lists.newArrayList();
            permFeaturePageDto.setAppCode(tabResourceList.get(0).getAppCode());
            permFeaturePageDto.setPermGroupId(permGroupId);
            permFeaturePageDto.setGroupCode(groupVO.getGroupCode());
            pages = groupVO.getPages();
            if (!CollectionUtils.isEmpty(groupVO.getPageGroups())) {
                for (PageGroup pageGroup : groupVO.getPageGroups()) {
                    pages.addAll(pageGroup.getPages());
                }
            }
            // 权限id
            String permId;

            // 获取角色页面权限
            String[] columnNames = new String[]{"app_code", "group_id", "group_code", "perm_domain_id"};
            Operator[] operators = new Operator[]{Operator.EQ, Operator.EQ, Operator.EQ, Operator.IS_NULL};
            Object[] columnValues = new Object[]{permFeaturePageDto.getAppCode(), permFeaturePageDto.getPermGroupId(), permFeaturePageDto.getGroupCode(), null};
            SingleResponse<BOList> rolePermByComplex = BoServiceUtils.findListByComplex(ModelConst.T_ROLE_PERM, columnNames, columnValues, operators);
            log.info("------------------------通过应用编码、角色组id、分组编码获取角色权限列表：{}------------------------", JSONObject.toJSONString(rolePermByComplex));

            // 角色权限表中存在数据，使用之前的权限id
            if (rolePermByComplex.getData().getTotal() > 0) {
                permId = String.valueOf(rolePermByComplex.getData().getData().get(0).get("perm_id"));
            } else {
                permId = UUID.randomUUID().toString().replaceAll("-", "");
                createRolePermByPage(permFeaturePageDto, roleId, permId);
            }
            permFeaturePageDto.setPermId(permId);

            // 设置组件权限
            for (Page page : pages) {
                // 获取资源类型为按钮并且页面编码满足条件的数据
                List<ResourceDto> buttonResourceList = appResourceList.stream().filter(resourceDto ->
                        ResourceTypeEnum.BUTTON.getCode().equals(resourceDto.getType()) && page.getCode().equals(resourceDto.getPageCode())).collect(Collectors.toList());
                PageGroupDto pageGroupDto = new PageGroupDto();
                Map<String, List<PageComponentDto>> pageMap = Maps.newHashMap();
                List<PageComponentDto> pageComponentDtoList = Lists.newArrayList();
                for (ResourceDto button : buttonResourceList) {
                    PageComponentDto pageComponentDto = new PageComponentDto();
                    pageComponentDto.setComponentCode(button.getComponentCode());
                    //组件权限,通过二进制位控制，1 2 4 8 16 （1可读 2可写 3可读可写，以此类推）
                    pageComponentDto.setPerm(3);
                    pageComponentDtoList.add(pageComponentDto);
                }
                pageMap.put(page.getCode(), pageComponentDtoList);
                pageGroupDto.setPageMap(pageMap);
                pageGroupList.add(pageGroupDto);
            }
            permFeaturePageDto.setPageGroupList(pageGroupList);
            log.info("------------------------更新角色组页面权限，页面资源数据：{}------------------------", JSONObject.toJSONString(permFeaturePageDto));
            SingleResponse<?> singleResponse = this.permService.updateAppPageAll(permFeaturePageDto);
            if (!singleResponse.isSuccess()) {
                Exceptions.throwBizException(new BizException(singleResponse.getErrCode(), singleResponse.getErrMessage(), singleResponse.getCorrectGuid()));
            }
        }
    }

    /**
     * 删除角色组菜单权限
     *
     * @param appCode 应用编码
     * @param roleId  系统管理角色id
     */
    private void removeAppMenu(String appCode, String roleId) {
        // 获取角色权限
        String[] columnNames = new String[]{"role_id", "app_code", "group_code", "perm_domain_id"};
        Operator[] operators = new Operator[]{Operator.EQ, Operator.EQ, Operator.IS_NULL, Operator.IS_NULL};
        Object[] columnValues = new Object[]{roleId, appCode, null, null};
        SingleResponse<BOList> rolePermByComplex = BoServiceUtils.findListByComplex(ModelConst.T_ROLE_PERM, columnNames, columnValues, operators);
        log.info("------------------------通过角色id、应用编码、分组编码获取角色权限列表：{}------------------------", JSONObject.toJSONString(rolePermByComplex));
        if (rolePermByComplex.getData().getTotal() == 0) {
            return;
        }
        // 设置角色权限
        PermFeatureMenuDto permFeatureMenuDto = new PermFeatureMenuDto();
        permFeatureMenuDto.setAppCode(appCode);
        permFeatureMenuDto.setPermGroupId(String.valueOf(rolePermByComplex.getData().getData().get(0).get("group_id")));
        permFeatureMenuDto.setPermId(String.valueOf(rolePermByComplex.getData().getData().get(0).get("perm_id")));
        permFeatureMenuDto.setMenuBarItemsMap(Maps.newHashMap());

        // 更新菜单权限
        log.info("------------------------更新角色组菜单权限，菜单资源数据：{}------------------------", JSONObject.toJSONString(permFeatureMenuDto));
        SingleResponse<?> singleResponse = this.permService.updateAppMenuAll(permFeatureMenuDto);
        if (!singleResponse.isSuccess()) {
            Exceptions.throwBizException(new BizException(singleResponse.getErrCode(), singleResponse.getErrMessage(), singleResponse.getCorrectGuid()));
        }
    }

    /**
     * 删除角色组页面权限
     *
     * @param appCode 应用编码
     * @param roleId  系统管理角色id
     */
    private void removeAppPage(String appCode, String roleId) {
        // 获取角色权限
        String[] columnNames = new String[]{"role_id", "app_code", "group_code", "perm_domain_id"};
        Operator[] operators = new Operator[]{Operator.EQ, Operator.EQ, Operator.IS_NOT_NULL, Operator.IS_NULL};
        Object[] columnValues = new Object[]{roleId, appCode, null, null};
        SingleResponse<BOList> rolePermByComplex = BoServiceUtils.findListByComplex(ModelConst.T_ROLE_PERM, columnNames, columnValues, operators);
        log.info("------------------------通过角色id、应用编码、分组编码获取角色权限列表：{}------------------------", JSONObject.toJSONString(rolePermByComplex));
        if (rolePermByComplex.getData().getTotal() == 0) {
            return;
        }
        // 根据groupCode循环调用更新页面权限接口
        for (Map<String, Object> rolePerm : rolePermByComplex.getData().getData()) {
            // 设置页面权限
            PermFeaturePageDto permFeaturePageDto = new PermFeaturePageDto();
            permFeaturePageDto.setAppCode(appCode);
            permFeaturePageDto.setPermGroupId(String.valueOf(rolePerm.get("group_id")));
            permFeaturePageDto.setGroupCode(String.valueOf(rolePerm.get("group_code")));
            permFeaturePageDto.setPermId(String.valueOf(rolePerm.get("perm_id")));
            permFeaturePageDto.setPageGroupList(Lists.newArrayList());

            // 更新页面权限
            log.info("------------------------更新角色组页面权限，页面资源数据：{}------------------------", JSONObject.toJSONString(permFeaturePageDto));
            SingleResponse<?> singleResponse = this.permService.updateAppPageAll(permFeaturePageDto);
            if (!singleResponse.isSuccess()) {
                Exceptions.throwBizException(new BizException(singleResponse.getErrCode(), singleResponse.getErrMessage(), singleResponse.getCorrectGuid()));
            }
        }
    }

    /**
     * 删除角色组领域模型权限
     *
     * @param appCode 应用编码
     * @param roleId  系统管理角色id
     */
    private void removeAppDomain(String appCode, String roleId) {
        // 获取应用下所有领域模型权限信息
        SingleResponse<?> appPage = getAppDomain(appCode);
        AppAllInOne AppAllInOne = ObjectMapperUtils.fromJSON(ObjectMapperUtils.toJSONString(appPage.getData()), AppAllInOne.class);

        // 获取角色组id
        String[] columnNames = new String[]{"app_code", "role_id"};
        Operator[] operators = new Operator[]{Operator.EQ, Operator.EQ};
        Object[] columnValues = new Object[]{appCode, roleId};
        SingleResponse<BOList> rolePermBOListByComplex = BoServiceUtils.findListByComplex(ModelConst.T_ROLE_PERM, columnNames, columnValues, operators);
        log.info("------------------------通过应用编码、角色id获取角色权限列表：{}------------------------", JSONObject.toJSONString(rolePermBOListByComplex));
        String permGroupId = String.valueOf(rolePermBOListByComplex.getData().getData().get(0).get("group_id"));
        // 设置领域模型属性值
        PermDomainDto permDomainDto = new PermDomainDto();
        permDomainDto.setAppCode(appCode);
        permDomainDto.setPermGroupId(permGroupId);
        List<PermDomainDataServiceDto> permDomainDataServiceDtoList = Lists.newArrayList();

        AppAllInOne.getGroupVOS().forEach(groupVO -> groupVO.getDomainModels().forEach(domainModel -> {
            PermDomainDataServiceDto permDomainDataServiceDto = new PermDomainDataServiceDto();

            // 获取领域模型编码
            String domainCode = domainModel.getCode();
            permDomainDataServiceDto.setDomainCode(domainCode);

            // 获取角色领域模型权限
            String[] columns = new String[]{"app_code", "group_id", "domain_code", "perm_id"};
            Operator[] ops = new Operator[]{Operator.EQ, Operator.EQ, Operator.EQ, Operator.IS_NULL};
            Object[] Values = new Object[]{appCode, permGroupId, domainCode, null};
            SingleResponse<BOList> rolePermByComplex = BoServiceUtils.findListByComplex(ModelConst.T_ROLE_PERM, columns, Values, ops);
            log.info("------------------------通过应用编码、角色组id、领域模型编码获取角色权限列表：{}------------------------", JSONObject.toJSONString(rolePermByComplex));
            String permDomainId = String.valueOf(rolePermByComplex.getData().getData().get(0).get("perm_domain_id"));
            permDomainDataServiceDto.setPermDomainId(permDomainId);

            // 设置数据模型集合
            Map<String, ModelDataDto> modelDataDtoMap = Maps.newHashMap();
            for (BizSchema bizSchema : domainModel.getBizSchemas()) {
                ModelDataDto modelDataDto = new ModelDataDto();
                // 设置模型高级权限规则，默认为空
                modelDataDto.setModelDataHighDtoList(Lists.newArrayList());

                // 设置行权限为0
                ModelDataRowDto modelDataRowDto = new ModelDataRowDto();
                modelDataRowDto.setRowType(0);
                modelDataDto.setModelDataRowDto(modelDataRowDto);

                // 设置模型操作权限
                modelDataDto.setModelDataOperatDtoList(Lists.newArrayList());

//                // 设置列权限
//                List<ModelDataColDto> modelDataColDtoList = Lists.newArrayList();
//                bizSchema.getProperties().forEach(properties -> {
//                    ModelDataColDto modelDataColDto = new ModelDataColDto();
//                    modelDataColDto.setColName(properties.getCode());
//                    // 1可见--不可写，2不可见--可写，3可见--可写，不可见--不可写则不传参数。默认给可见可写权限
//                    modelDataColDto.setPerm(3);
//                    modelDataColDtoList.add(modelDataColDto);
//                });
                modelDataDto.setModelDataColDtoList(Lists.newArrayList());
                modelDataDtoMap.put(bizSchema.getCode(), modelDataDto);
            }
            permDomainDataServiceDto.setModelDataDtoMap(modelDataDtoMap);
            permDomainDataServiceDtoList.add(permDomainDataServiceDto);
        }));
        permDomainDto.setPermDomainDataServiceDtoList(permDomainDataServiceDtoList);
        log.info("------------------------更新角色组领域模型权限，领域模型资源数据：{}------------------------", JSONObject.toJSONString(permDomainDto));
        SingleResponse<?> singleResponse = this.permService.updateAppDomainAll(permDomainDto);
        if (!singleResponse.isSuccess()) {
            Exceptions.throwBizException(new BizException(singleResponse.getErrCode(), singleResponse.getErrMessage(), singleResponse.getCorrectGuid()));
        }
    }

    /**
     * 通过页面权限新增角色权限数据
     *
     * @param permFeaturePageDto 页面权限
     * @param roleId             角色id
     * @param permId             权限id
     */
    private void createRolePermByPage(PermFeaturePageDto permFeaturePageDto, String roleId, String permId) {
        // 新增角色权限
        Map<String, Object> rolePermMap = Maps.newHashMap();
        rolePermMap.put("role_id", roleId);
        rolePermMap.put("app_code", permFeaturePageDto.getAppCode());
        rolePermMap.put("group_id", permFeaturePageDto.getPermGroupId());
        rolePermMap.put("perm_id", permId);
        rolePermMap.put("perm_domain_id", null);
        rolePermMap.put("group_code", permFeaturePageDto.getGroupCode());
        rolePermMap.put("domain_code", null);
        log.info("------------------------创建系统管理角色权限数据：{}------------------------", JSONObject.toJSONString(rolePermMap));
        BoServiceUtils.createBo(ModelConst.T_ROLE_PERM, Collections.singletonList(rolePermMap));
    }

    /**
     * 通过菜单权限新增角色权限数据
     *
     * @param permFeaturePageDto 菜单权限
     * @param roleId             角色id
     * @param permId             权限id
     */
    private void createRolePermByMenu(PermFeatureMenuDto permFeaturePageDto, String roleId, String permId) {
        // 新增角色权限
        Map<String, Object> rolePermMap = Maps.newHashMap();
        rolePermMap.put("role_id", roleId);
        rolePermMap.put("app_code", permFeaturePageDto.getAppCode());
        rolePermMap.put("group_id", permFeaturePageDto.getPermGroupId());
        rolePermMap.put("perm_id", permId);
        rolePermMap.put("perm_domain_id", null);
        rolePermMap.put("group_code", null);
        rolePermMap.put("domain_code", null);
        log.info("------------------------创建系统管理角色权限数据：{}------------------------", JSONObject.toJSONString(rolePermMap));
        BoServiceUtils.createBo(ModelConst.T_ROLE_PERM, Collections.singletonList(rolePermMap));
    }

    /**
     * 通过领域模型权限新增角色权限数据
     *
     * @param permDomainDto 领域模型权限
     * @param roleId        角色id
     * @param permDomainId  领域模型权限id
     * @param domainCode    领域模型编码
     */
    private void createRolePermByDomain(PermDomainDto permDomainDto, String roleId, String permDomainId, String domainCode) {
        // 新增角色权限
        Map<String, Object> rolePermMap = Maps.newHashMap();
        rolePermMap.put("role_id", roleId);
        rolePermMap.put("app_code", permDomainDto.getAppCode());
        rolePermMap.put("group_id", permDomainDto.getPermGroupId());
        rolePermMap.put("perm_domain_id", permDomainId);
        rolePermMap.put("perm_id", null);
        rolePermMap.put("group_code", null);
        rolePermMap.put("domain_code", domainCode);
        log.info("------------------------创建系统管理角色权限数据：{}------------------------", JSONObject.toJSONString(rolePermMap));
        BoServiceUtils.createBo(ModelConst.T_ROLE_PERM, Collections.singletonList(rolePermMap));
    }

    /**
     * 获取角色id差集
     *
     * @param rolePermBOList 修改之前的应用列表
     * @param resourceList   修改之后的应用列表
     * @return 角色id差集
     */
    private List<String> getRemoveList(SingleResponse<BOList> rolePermBOList, List<ResourceDto> resourceList) {
        // 获取修改之前的appCode列表
        List<String> oldAppCodeList = rolePermBOList.getData().getData().stream().map(rolePerm -> String.valueOf(rolePerm.get("app_code"))).distinct().collect(Collectors.toList());

        // 获取修改之后的appCode列表
        List<String> newAppCodeList = resourceList.stream().map(ResourceDto::getAppCode).distinct().collect(Collectors.toList());

        // 获取所有的appCode列表
        List<String> allAppCodeList = Lists.newArrayList(oldAppCodeList);
        allAppCodeList.addAll(newAppCodeList);

        // 获取需要删除的appCode列表
        List<String> removeAppCodeList = Lists.newArrayList(allAppCodeList);
        removeAppCodeList.removeAll(newAppCodeList);
        return removeAppCodeList;
    }

    /**
     * 通过应用编码获取页面元数据信息
     *
     * @param appCode 应用编码
     * @return 响应结果
     */
    private SingleResponse<?> getMenuTree(String appCode) {
        HttpHeaders headers = HttpClients.buildHttpHeaders(appCode);
        HttpEntity<String> request = new HttpEntity<>(null, headers);
        // 获取请求地址
        String requestUrl = HttpClients.getUrl(appCode, RoleApi.SUFFIX_URL);
        log.info("application service request = {},requestUrl = {}", request, requestUrl);
        SingleResponse<?> response = restTemplate.getForObject(requestUrl, SingleResponse.class);
        log.info("----------application service response：{}----------------", response);
        if (response == null || response.getData() == null) {
            Exceptions.throwBizException(ErrorCodeEnum.GET_PERMISSION_EXCEPTION);
        }
        return response;
    }

    /**
     * 通过应用编码获取应用页面信息
     *
     * @param appCode 应用编码
     * @return 响应结果
     */
    private SingleResponse<?> getAppPage(String appCode) {
        HttpHeaders headers = HttpClients.buildHttpHeaders(appCode);
        HttpEntity<String> request = new HttpEntity<>(null, headers);
        // 获取请求地址
        String requestUrl = HttpClients.getUrl(appCode, RoleApi.App_GET_PAGE_URL);
        log.info("application service request = {},requestUrl = {}", request, requestUrl);
        SingleResponse<?> response = restTemplate.getForObject(requestUrl, SingleResponse.class);
        log.info("----------application service response：{}----------------", JSONObject.toJSONString(response));
        if (response == null || response.getData() == null) {
            Exceptions.throwBizException(ErrorCodeEnum.BIZ_REMOST_REQ_ERR);
        }
        return response;
    }

    /**
     * 通过应用编码获取应用模型信息
     *
     * @param appCode 应用编码
     * @return 响应结果
     */
    private SingleResponse<?> getAppDomain(String appCode) {
        HttpHeaders headers = HttpClients.buildHttpHeaders(appCode);
        HttpEntity<String> request = new HttpEntity<>(null, headers);
        // 获取请求地址
        String requestUrl = HttpClients.getUrl(appCode, RoleApi.App_GET_DOMAIN_URL);
        log.info("application service request = {},requestUrl = {}", request, requestUrl);
        SingleResponse<?> response = restTemplate.getForObject(requestUrl, SingleResponse.class);
        log.info("----------application service response：{}----------------", response);
        if (response == null || response.getData() == null) {
            Exceptions.throwBizException(ErrorCodeEnum.BIZ_REMOST_REQ_ERR);
        }
        return response;
    }

    //静态文件处理
    private void handleResource(String name) {
        try {
            InputStream rs = this.getClass().getClassLoader().getResourceAsStream(name);
            if (Objects.isNull(rs)) {
                log.warn("文件名：{}，流为空", name);
            }
            String path = "/".concat(name);
            File file = new File(path);
            if (file.exists()) {
                file.delete();
            }
            FileOutputStream fos = new FileOutputStream(path);
            byte[] b = new byte[1024];
            while ((rs.read(b)) != -1) {
                fos.write(b);// 写入数据
            }
            rs.close();
            fos.close();// 保存数据
            log.info("文件写入完成....");
        } catch (IOException e) {
            log.error("【handleResource】 异常：", e);
        }
    }
}
